Compare commits

..
Author SHA1 Message Date
Kit Langton e84efb181c test(httpapi): smoke test sdk against effect server 2026-04-28 14:28:11 -04:00
Kit Langton 2e8d690ab1 fix(httpapi): finish sdk openapi parity (#24827) 2026-04-28 14:24:10 -04:00
Kit Langton 1ff8d289af fix(tui): handle Zed selection byte offsets (#24825) 2026-04-28 14:09:39 -04:00
Dax d54ffbda1c tui: ignore invalid custom themes to prevent startup crashes (#24645) 2026-04-28 13:58:55 -04:00
Kit Langton c00058ed7a fix(httpapi): align request body openapi shape (#24811) 2026-04-28 12:55:37 -04:00
James Long 2c2fc3499b feat(core): store relative path for sessions (#24704) 2026-04-28 11:51:24 -04:00
Kit Langton ea3c6c3481 fix(httpapi): document instance query parameters (#24809) 2026-04-28 11:10:00 -04:00
opencode-agent[bot] 9b68b7195a chore: generate 2026-04-28 15:05:37 +00:00
Kit Langton 7739cc53b4 refactor(httpapi): fork server startup by flag (#24799) 2026-04-28 11:02:35 -04:00
David Hill 3fa78a8b01 docs: bump GitHub stars count to 150K (#24792) 2026-04-28 09:24:46 -04:00
Kit Langton e57d0c2fee fix(httpapi): document tui bad request responses
Document legacy 400 bad-request responses on TUI Effect HttpApi payload-validation endpoints and cover them with OpenAPI parity tests.
2026-04-28 09:23:54 -04:00
Kit Langton 2a4f2bf527 fix(httpapi): align sync seq validation
Reject negative and fractional sync sequence values in Effect HttpApi schemas so replay/history validation matches the legacy Hono routes.
2026-04-28 09:22:49 -04:00
Brendan AllanandAndrew Avsenin aa07f38b07 fix(app): preserve per-workspace icon override from localStorage (#24738)
Co-authored-by: Andrew Avsenin <snatvb@ya.ru>
2026-04-28 19:37:40 +08:00
Brendan Allan 9d1f17d836 fix(ui): remove redundant flex overrides in tool components (#24749) 2026-04-28 15:51:18 +08:00
github-actions[bot] b420952e59 Update VOUCHED list
https://github.com/anomalyco/opencode/issues/24732#issuecomment-4332442679
2026-04-28 04:53:58 +00:00
opencode-agent[bot] bb9e445257 chore: generate 2026-04-28 04:45:24 +00:00
Aiden Cline 528fb1d404 fix: sanitize tools for moonshot (#24730) 2026-04-27 23:44:21 -05:00
Brendan Allan c8d9f7aa89 refactor(app): load sync state through TanStack Query (#23792) 2026-04-28 04:24:30 +00:00
opencode-agent[bot] cd7ec93cdf chore: generate 2026-04-28 02:34:43 +00:00
Kit Langton 796b652d2b fix(httpapi): preserve mcp oauth error parity (#24706) 2026-04-27 22:33:21 -04:00
Kit Langton 4d74849c1a fix(tui): keep Zed context polling responsive (#24711) 2026-04-27 22:24:04 -04:00
opencode-agent[bot] 937a7c48a5 chore: update nix node_modules hashes 2026-04-28 02:22:33 +00:00
Kit Langton 704eb00de4 chore: bump effect beta (#24705) 2026-04-27 21:58:11 -04:00
opencode-agent[bot] bad4599bf9 chore: generate 2026-04-28 01:50:04 +00:00
Kit Langton 892fd85ba7 fix(httpapi): preserve provider oauth authorize parity (#24703) 2026-04-27 21:48:50 -04:00
opencode-agent[bot] 0eaa47d857 chore: generate 2026-04-28 00:54:28 +00:00
Kit Langton faca24d487 fix(httpapi): align session boolean query parsing (#24693) 2026-04-27 20:53:27 -04:00
Kit Langton c103202ad5 test(httpapi): cover session json parity (#24682) 2026-04-27 19:48:57 -04:00
Kit Langton ce78a4265d fix(session): remove compaction summary dividers (#24677) 2026-04-27 18:15:11 -04:00
Kit Langton c4a2353ac3 fix(session): omit undefined optional fields (#24676) 2026-04-27 17:50:09 -04:00
Kit Langton 576efed196 fix(httpapi): preserve optional session fields (#24671) 2026-04-27 21:38:28 +00:00
opencode-agent[bot] dfc0075f90 chore: generate 2026-04-27 20:52:42 +00:00
Kit Langton acd15dcc8a test(httpapi): cover full OpenAPI route inventory (#24667) 2026-04-27 16:51:24 -04:00
Kit Langton 139c4fd555 fix(session): harden shell cancellation (#24553) 2026-04-27 20:47:18 +00:00
Cas e0f3df8252 fix(tui): consume Enter in dialog useKeyboard handlers (#23390) 2026-04-27 15:31:49 -05:00
opencode-agent[bot] 9cd2e3a1c3 chore: generate 2026-04-27 20:31:05 +00:00
Kit Langton f584f80219 test(httpapi): verify reflected route mounts (#24663) 2026-04-27 16:29:58 -04:00
Kit Langton 45eac589f8 fix(tui): preserve Zed context on terminal focus (#24662) 2026-04-27 16:25:37 -04:00
James Long fab1768826 feat(core): file context improvements and option to disable (#24661) 2026-04-27 16:10:13 -04:00
Kit Langton 51fc10e407 fix(httpapi): enforce instance route parity (#24660) 2026-04-27 16:07:31 -04:00
opencode-agent[bot] 7a1c8465f5 chore: generate 2026-04-27 19:38:33 +00:00
Kit Langton 5290e9ca7e fix(tui): stabilize Zed editor context polling (#24656) 2026-04-27 15:37:18 -04:00
Aiden Cline c361c2953f fix: ensure toolStreaming is set to off by default when using non anthropic models with anthropic sdk (#24642) 2026-04-27 14:16:00 -05:00
opencode-agent[bot] ccb7669736 chore: generate 2026-04-27 18:34:44 +00:00
Dax f25f1485d5 refactor: remove module barrels (#24554) 2026-04-27 14:33:33 -04:00
Kit Langton 55ecb06748 fix(httpapi): accept empty session create body (#24640) 2026-04-27 17:17:11 +00:00
Kit Langton dc6991e5a8 fix(httpapi): mount workspace bridge routes (#24626) 2026-04-27 12:52:48 -04:00
Aiden Cline 738b3065dc tweak: make interleaved reasoning_content default to true for openai compat deepseek setups (#24630) 2026-04-27 10:17:38 -05:00
opencode-agent[bot] 26cc537cb1 chore: generate 2026-04-27 14:46:00 +00:00
Seashore ShiandSeashore ede354b0e6 docs: fix duplicated word in CLI env var table (#24614)
Co-authored-by: Seashore <ss@SeashoredeMac-mini.local>
2026-04-27 09:44:53 -05:00
Jack 61eabfc60c update Go DeepSeek flash limits for cache pricing drop (#24592) 2026-04-27 17:02:27 +08:00
opencode-agent[bot] 2789b770aa chore: generate 2026-04-27 05:40:37 +00:00
Luke Parker 8718b98ee1 fix: pass workspace symbol query to experimental LSP tool (#24576) 2026-04-27 05:39:36 +00:00
opencode-agent[bot] c8b2f987f9 chore: generate 2026-04-27 05:39:13 +00:00
Frank 52b55b826f Merge branch 'fix/usage-chart' into dev 2026-04-27 01:37:52 -04:00
Frank e8c20235b8 zen: coupons 2026-04-27 01:36:28 -04:00
opencode-agent[bot] 17701628bd chore: generate 2026-04-27 05:18:33 +00:00
0efc6163f1 fix(opencode): agent create generates permissions field with deny ins… (#24482)
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2026-04-27 00:17:08 -05:00
Jack 1e191ba815 update Go DeepSeek request estimates for cache pricing changes (#24575) 2026-04-27 13:06:51 +08:00
Aiden Cline f19d863689 ignore: split up reasoning transforms (#24574) 2026-04-26 23:57:32 -05:00
Frank 4a1ef327ca sync 2026-04-27 00:52:54 -04:00
Aiden Cline 025a6392ce fix: default tool call streaming to false for google vertex (#24573) 2026-04-26 23:42:23 -05:00
opencode e578c442be sync release versions for v1.14.28 2026-04-27 04:23:44 +00:00
opencode-agent[bot] 0cecb1bff2 chore: generate 2026-04-27 04:05:59 +00:00
Frank 5d8971c1ed go: add deepseek icon 2026-04-27 00:04:44 -04:00
Dax a9b62d67df Refactor npm config handling (#24565) 2026-04-27 03:54:59 +00:00
Luke Parker 3525e61906 fix: ignore GitHub Actions changelog contributor (#24567) 2026-04-27 03:47:04 +00:00
github-actions[bot] 059e6c46db Update VOUCHED list
https://github.com/anomalyco/opencode/issues/24563#issuecomment-4323944984
2026-04-27 03:30:38 +00:00
Frank 5cf195e0af go: models endpoint 2026-04-26 23:02:18 -04:00
opencode 244d1debe4 sync release versions for v1.14.27 2026-04-27 02:09:07 +00:00
opencode-agent[bot] 35734b42fe chore: update nix node_modules hashes 2026-04-27 01:55:51 +00:00
Sebastian a3128e32c5 upgrade opentui to 0.1.105 (#24555) 2026-04-26 21:39:40 -04:00
Dax 5f8a72bfc4 fix(tui): hide provider checks before onboarding (#24551) 2026-04-27 01:18:26 +00:00
Kit Langton 418a1cf5f3 feat(httpapi): bridge tui routes (#24548) 2026-04-27 01:17:48 +00:00
Dax Raad 60ebd074ac core: refactor Installation service to use a single consolidated result object
Reorganizes the Installation service implementation by grouping info, method, latest, and upgrade methods into a single result object. This improves code locality and makes the service interface more maintainable. Also adds a clarifying comment explaining why the package manager's resolver is used for version lookups (to ensure registries, mirrors, auth, proxies, and dist-tags match upgrade behavior).
2026-04-26 21:05:42 -04:00
Kit Langton 216dd363e8 feat(httpapi): bridge pty routes (#24547) 2026-04-26 21:05:16 -04:00
Luke Parker 141f33d24b feat: configurable shell selection + desktop settings UI (#20602) 2026-04-27 00:54:55 +00:00
opencode-agent[bot] c4d8a8183e chore: generate 2026-04-26 23:56:15 +00:00
Kit Langton 58244eb687 feat(httpapi): bridge event stream (#24518) 2026-04-26 19:55:13 -04:00
Dax Raad e9071b0a80 tui: remove excessive debug logging from workspace creation flow to reduce terminal output noise 2026-04-26 19:33:40 -04:00
OpeOginniandAiden Cline c68907ece2 fix(tui): update toast duration handling to use default value (#23395)
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
2026-04-26 17:27:02 -05:00
opencode af3998c8a6 sync release versions for v1.14.26 2026-04-26 21:01:16 +00:00
opencode-agent[bot] fad2618757 chore: update nix node_modules hashes 2026-04-26 20:45:18 +00:00
Sebastian 21e01dbe04 upgrade opentui to 0.1.104 (#24531) 2026-04-26 22:31:33 +02:00
JackandFrank 3beadeebff feat(go): add Go model listing endpoint (#24304)
Co-authored-by: Frank <frank@anoma.ly>
2026-04-26 14:46:49 -04:00
Jermiah Joseph dcee1c3642 fix(editor): reject lock files with no workspace match for cwd (#24323) 2026-04-26 14:21:29 -04:00
Aiden Cline 00d1a7e090 chore: rm empty file 2026-04-26 12:32:41 -05:00
opencode-agent[bot] bbb56c2a88 chore: generate 2026-04-26 17:14:24 +00:00
Frank 5186c6964b sync 2026-04-26 13:11:09 -04:00
Frank 79c66e353f sync 2026-04-26 12:50:03 -04:00
opencode-agent[bot] 41f5e8a861 chore: generate 2026-04-26 16:25:19 +00:00
Kit Langton c5b67927af feat(httpapi): bridge remaining session routes (#24510) 2026-04-26 12:24:19 -04:00
opencode-agent[bot] 301ecb185e chore: generate 2026-04-26 16:01:07 +00:00
Kit Langton 151df05eeb feat(httpapi): bridge session message mutations (#24487) 2026-04-26 12:00:02 -04:00
opencode-agent[bot] 55adcdfd07 chore: generate 2026-04-26 15:51:31 +00:00
Kit Langton daaa2e5911 feat(httpapi): bridge session lifecycle routes (#24486) 2026-04-26 11:50:26 -04:00
opencode-agent[bot] daff119fe4 chore: generate 2026-04-26 15:50:09 +00:00
Kit Langton e0d1ff42c0 feat(httpapi): bridge session read routes (#24485) 2026-04-26 11:49:11 -04:00
opencode-agent[bot] de413c56ae chore: generate 2026-04-26 15:32:42 +00:00
Kit Langton da61b0290a feat(httpapi): bridge sync routes (#24484) 2026-04-26 11:31:46 -04:00
Dax Raad d03e6cedde ci: update team assignments in github-triage
Update team member assignments in the triage tool:
- Remove thdxr from tui and core teams
- Add simonklee to tui team
- Add kitlangton to core team
2026-04-26 11:18:59 -04:00
Jack 7feb6ab962 fix(docs): correct OpenCode Go DeepSeek endpoints (#24500) 2026-04-26 23:15:55 +08:00
opencode-agent[bot] 854d4b7a53 chore: generate 2026-04-26 15:13:18 +00:00
Kit Langton aa5999b188 feat(httpapi): bridge workspace mutations (#24483) 2026-04-26 11:12:04 -04:00
opencode-agent[bot] 37c5eab6f8 chore: generate 2026-04-26 14:48:31 +00:00
Kit Langton 6daa2b9aeb feat(httpapi): bridge experimental session list (#24478) 2026-04-26 10:47:24 -04:00
Ariane Emory 5a5a2e5fa0 fix: correct typo in comment (#24420) 2026-04-26 00:26:48 -05:00
opencode-agent[bot] 95c43fc675 chore: update nix node_modules hashes 2026-04-26 05:19:08 +00:00
Aiden Cline e7053c41f4 fix: bump openrouter sdk version to resolve deepseek reasoning issue (bug was in sdk pkg) (#24435) 2026-04-26 00:05:16 -05:00
Dax Raad fc6d4b4010 core: Add User-Agent header to identify client version in HTTP requests 2026-04-25 23:51:23 -04:00
Frank 2893588016 sync 2026-04-25 23:23:48 -04:00
Kit Langton f2d4d816fb test(provider): avoid plugin dependency install timeout (#24416) 2026-04-26 02:11:25 +00:00
opencode-agent[bot] 097d930668 chore: generate 2026-04-26 01:55:57 +00:00
Kit Langton 7cab6824d1 feat(httpapi): bridge experimental tool routes (#24407) 2026-04-25 21:54:58 -04:00
opencode-agent[bot] f77277a69e chore: generate 2026-04-25 23:28:25 +00:00
Kit Langton 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 Langton a14c22d4e9 feat(httpapi): bridge mcp control endpoints (#24403) 2026-04-25 19:16:19 -04:00
Kit Langton 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 Langton 5904f599a9 feat(httpapi): bridge project git init endpoint (#24394) 2026-04-25 18:42:02 -04:00
Kit Langton 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 Langton 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 Langton b4f4134e81 feat(httpapi): bridge instance dispose endpoint (#24368) 2026-04-25 15:24:07 -04:00
Kit Langton 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 Langton 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 Langton 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 Langton 05661c60ff feat(httpapi): bridge file search endpoints (#24356) 2026-04-25 14:12:54 -04:00
Kit Langton 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 Langton 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 Cline 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 Langton 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
Dax 1d728fc627 feat: add startup debug command (#24310) 2026-04-25 15:08:19 +00:00
Dax 62ef2a2207 refactor: rename shared package to core (#24309) 2026-04-25 10:59:17 -04:00
Dax 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 Langton 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
Dax 66f93035b0 fix permission config order (#24222) 2026-04-25 13:18:42 +00:00
Simon Klee 9ff999cc2b tool/lsp: include request details in permission metadata (#24139) 2026-04-25 14:21:35 +02:00
Kit Langton 4877eccc0d Fix shell cwd after login startup (#24215) 2026-04-25 01:14:52 -04:00
Aiden Cline 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 Hellstrom 49894330d9 fix(build): add prettier to devDependencies (#23255) 2026-04-24 22:47:05 -04:00
Luke Parker 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 Parker 386091b79a fix: validate beta before pushing (#24230) 2026-04-25 10:32:41 +10:00
Luke Parker 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 Langton 97eb9fdee8 test(httpapi): cover hono bridge middleware (#24216) 2026-04-24 18:03:51 -04:00
Kit Langton 5a04de231e refactor(ripgrep): migrate result schemas to effect (#24213) 2026-04-24 17:42:52 -04:00
Kyle AltendorfAiden 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 Cline 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 Cline 872cdff2ab ignore: denounce ai spammer 2026-04-24 17:37:28 -04:00
Kit Langton 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 Langton cf45a8d807 refactor(schema): decode effect schemas directly (#24169) 2026-04-24 17:11:52 -04:00
Kit Langton 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
Sebastian 3a5507de95 Use OpenTUI theme detection for initial TUI mode, again (#23846) 2026-04-24 17:28:07 +02:00
Aiden Cline 86715fecc4 fix: ensure assistant messages always have reasoning on them for deepseek (#24180) 2026-04-24 11:10:47 -04:00
07akioni 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 Langton 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 Langton 9f7ecd65e5 feat(httpapi): bridge file read endpoints (#24098) 2026-04-24 09:12:05 -04:00
Aiden Cline f8e939d96f fix: support max for deepseek (#24163) 2026-04-24 08:48:52 -04:00
黑墨水鱼andSimon Klee 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 Cline a882e958b3 fix: deepseek variants (#24157) 2026-04-24 08:34:48 -04:00
Simon Klee 2cda629c8d test(prompt): align shell placeholder expectation (#24147) 2026-04-24 13:00:11 +02:00
Brendan Allan 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 Allan 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 Allan 2e156b8990 fix(desktop): avoid relaunching without installing updates (#23806) 2026-04-24 13:27:36 +08:00
Brendan Allan 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 Langton e50a688ca3 feat(httpapi): bridge workspace read endpoints (#24062) 2026-04-23 17:32:02 -04:00
Aiden Cline 334ab4707c fix: account for additional openai retry case (#24063) 2026-04-23 17:31:43 -04:00
Aiden Cline 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 Langton 31d01d404a refactor(control-plane): migrate workspace DTO schemas (#24056) 2026-04-23 16:48:56 -04:00
Kit Langton 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 Long 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 Langton 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 Langton cd93533b1f refactor(bus): migrate BusEvent to Effect Schema (#24040) 2026-04-23 15:37:44 -04:00
Kit Langton 0590452456 refactor(schema): use Schema.Int and consolidate PositiveInt/NonNegativeInt (#24029) 2026-04-23 13:22:48 -04:00
Kit Langton 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 Langton 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 Langton 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 Dash 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 Langton 0517ab4695 refactor(session): migrate session domain to Effect Schema (#24005) 2026-04-23 11:30:02 -04:00
James Long bbf67d0fff fix(tui): render all non-synthetic text parts of a user message (#24009) 2026-04-23 11:24:40 -04:00
Shoubhit Dash 38deb0f3ee fix(npm): respect npmrc config (#24001) 2026-04-23 19:54:01 +05:30
Simon Klee 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 Allan 6002500bc0 feat(project): add icon_url_override field to projects (#23955) 2026-04-23 18:57:04 +08:00
Brendan Allan 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 Allan df27baa00d refactor: remove redundant pending check from working memo (#23929) 2026-04-23 13:15:02 +08:00
Aiden Cline 9730008543 tweak: codex model logic (#23925) 2026-04-23 00:29:56 -04:00
Luke Parker ac26394fcb fix(beta): PR resolvers/smoke check should typecheck all pacakges (#23913) 2026-04-23 00:25:41 -04:00
Luke Parker 6387b35a2d log session sdk errors (#23652) 2026-04-23 00:25:41 -04:00
opencode-agent[bot] 1cd4c92242 chore: generate 2026-04-23 00:25:40 -04:00
Luke Parker e383df4b17 feat: support pull diagnostics in the LSP client (C#, Kotlin, etc) (#23771) 2026-04-23 00:25:40 -04:00
Caleb Norton 58db41b4b9 chore: update nix bun version (#23881) 2026-04-23 00:25:40 -04:00
opencode-agent[bot] 5d133f2785 chore: generate 2026-04-23 00:25:39 -04:00
Jack e9b1d3b940 docs: add MiMo V2.5 to Go pages (#23876) 2026-04-23 00:25:39 -04:00
Steven T. Cramer 3a082a0efd fix(project): use git common dir for bare repo project cache (#19054) 2026-04-23 00:25:39 -04:00
opencode-agent[bot] 504fd1b373 chore: generate 2026-04-23 00:25:39 -04:00
Shoubhit Dash 574b2c2170 fix(session): improve session compaction (#23870) 2026-04-23 00:25:38 -04:00
opencode-agent[bot] fa8b7bc4d2 chore: generate 2026-04-23 00:25:38 -04:00
Shoubhit Dash 6196b81e0a fix(tui): fail fast on invalid session startup (#23837) 2026-04-23 00:25:38 -04:00
Brendan Allan d884ab73d5 fix: consolidate project avatar source logic (#23819) 2026-04-23 00:25:37 -04:00
opencode-agent[bot] 71d196d3cd chore: generate 2026-04-23 00:25:37 -04:00
Luke Parker 20756e0ee4 test: fix cross-spawn stderr race on Windows CI (#23808) 2026-04-23 00:25:37 -04:00
opencode-agent[bot] 894e638914 chore: generate 2026-04-23 00:25:37 -04:00
Luke Parker 8113a4360e fix: preserve BOM in text tool round-trips (#23797) 2026-04-23 00:25:36 -04:00
opencode-agent[bot] c819804638 chore: update nix node_modules hashes 2026-04-23 00:25:36 -04:00
Brendan Allan 06066dbb7b fix(app): improve icon override handling in project edit dialog (#23768) 2026-04-23 00:25:36 -04:00
Luke Parker 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 Langton ed802fd121 refactor(core): migrate MessageV2 errors to Schema-backed named errors (#23764) 2026-04-21 23:40:32 -04:00
Kit Langton 1593c3ed16 refactor(core): migrate MessageV2 internal Cursor to Effect Schema (#23763) 2026-04-21 23:28:33 -04:00
Kit Langton 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 Langton 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 Langton ad7ae7353f refactor(core): derive all schema.ts leaves' .zod via effect-zod walker (#23754) 2026-04-21 22:51:18 -04:00
NN708 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
Mathews BryanandMathews 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 Langton 2da6d860e0 refactor(core): derive provider schema .zod via effect-zod walker (#23753) 2026-04-21 17:49:24 -04:00
Kit Langton df0c1f649c refactor(core): migrate MessageV2 tool state schemas to Effect Schema (#23752) 2026-04-21 17:47:50 -04:00
Kit Langton d6dea3f3e0 chore(core): clean up after ConfigPermission Effect Schema migration (#23749) 2026-04-21 17:40:54 -04:00
Kit Langton 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 Langton b0f565b74a refactor(core): migrate ConfigPermission.Info to Effect Schema canonical (#23740) 2026-04-21 17:33:13 -04:00
Kit Langton 2ae64f426b refactor(core): migrate MessageV2.Format to Effect Schema (#23744) 2026-04-21 17:30:08 -04:00
Kit Langton 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 Smet 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 Cline 58232d896e fix: dont show variants for kimi models that dont support them (#23696) 2026-04-21 15:33:35 -04:00
Rahul IyerandAiden Cline 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 Langton 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 Cline e95474df05 fix: revert parts of a824064c4 which caused system theme regression (#23714) 2026-04-21 12:08:12 -04:00
Kit Langton 96a534d8c6 feat(core): bridge GET /config through experimental HttpApi (#23712) 2026-04-21 16:05:23 +00:00
Kit Langton 9579429276 test(opencode): consolidate session prompt tests into Effect style (#23710) 2026-04-21 15:54:40 +00:00
Aiden Cline 2486621ca1 chore: kill unused tool (#23701) 2026-04-21 11:31:20 -04:00
James Long b5acc2203c fix(core): fix permissions routing when using remote workspace (#23593) 2026-04-21 14:42:54 +00:00
Brendan Allan 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 Allan 811a7e9a8b feat(app): allow disabling progress bar in settings (#23674) 2026-04-21 19:10:50 +08:00
Brendan Allan febadc5589 fix(ui): correct diff render condition logic (#23670) 2026-04-21 18:49:04 +08:00
Luke Parker 92c005866b fix(core): use file:// URLs for local dynamic import() on Windows+Node (#23639) 2026-04-21 07:54:53 +00:00
OpeOginni 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 Allan 22d33c57af fix(app): properly wrap produce calls in setProjects (#23638) 2026-04-21 14:11:23 +08:00
JackandFrank 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 Allan 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 Allan 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 Allan 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 Long 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 Murdza 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
Jack 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 Yang 16caaa2229 fix(app): fall back to icon.url in sidebar avatar (#18747) 2026-04-20 19:32:54 +08:00
黑墨水鱼 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 Parker 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 Cline c6c56ac2cf tweak: rename tail_tokens -> preserve_recent_tokens (#23491) 2026-04-20 01:06:29 -05:00
Aiden Cline e539efe2b9 fix: patch arborist to get around bun bug (#23460) 2026-04-20 00:49:46 -05:00
Brendan Allan 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 Cline 8bc4f91fd9 fix: parallel edits sometimes would override each other (#23483) 2026-04-20 00:14:21 -05:00
Brendan Allan 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 Parker 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
Sebastian 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 Parker 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 Allan 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 Allan 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
Shoubhit DashandLukeParkerDev 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
Dax 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 Cline 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 Emory 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 Parker 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 Parker 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 Cline 78ca49a1bc test: fix bedrock test (#23351) 2026-04-18 17:46:15 -05:00
Ryan VogelandRyan Vogel 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 Cline e2e7a8d722 fix: ensure display: summarized is sent by default for bedrock (#23343) 2026-04-18 16:04:00 -05:00
Aiden Cline ce7923adaf chore: bump @ai-sdk/amazon-bedrock (#23341) 2026-04-18 16:00:46 -05:00
Dax 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 Langton 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 Cline 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 Langton b382d1a467 docs(effect): track schema migration progress with concrete file checklists (#23242) 2026-04-18 03:51:30 +00:00
Kit Langton 23f31475e7 refactor(config): migrate config.ts root Info to Effect Schema (#23241) 2026-04-18 03:44:35 +00:00
OpeOginni 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 Langton 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 Langton a6a4350d10 refactor(config): migrate permission.ts Info to Effect Schema (#23231) 2026-04-18 03:05:06 +00:00
Kit Langton 471b9f4dc4 refactor: use InstanceState context in worktree cleanup paths (#23019) 2026-04-17 23:04:16 -04:00
Kit Langton 24fb9b1296 fix: stop rewriting dev during release publish (#22982) 2026-04-18 02:53:19 +00:00
Kit Langton 3573019916 fix(generate): make openapi output deterministic by formatting in-place (#23228) 2026-04-17 22:31:21 -04:00
Kit Langton fc5b353144 refactor(config): migrate keybinds.ts to Effect Schema (#23227) 2026-04-18 02:28:45 +00:00
Kit Langton 1dd257b76a refactor: use instance state in small services (#23022) 2026-04-18 02:16:15 +00:00
Kit Langton 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 Langton 1fae784b81 feat(effect-zod): add ZodPreprocess annotation for pre-parse transforms (#23222) 2026-04-18 02:02:37 +00:00
Aiden Cline 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 Langton e6fd57165e refactor: remove ambient instance reads from lsp (#23023) 2026-04-17 21:47:59 -04:00
Kit Langton 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 Langton 826fd3350c refactor(config): migrate Server + Layout to Effect Schema (#23216) 2026-04-18 01:20:06 +00:00
Kit Langton 23a2d01282 fix(observability): standardize session telemetry attrs (#23213) 2026-04-17 21:14:23 -04:00
Kit Langton 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 Langton 36119ff173 feat(effect-zod): translate Schema.withDecodingDefault into zod .default() (#23207) 2026-04-17 20:55:38 -04:00
Kit Langton bb90f3bbf9 feat(effect-zod): translate well-known filters into native Zod methods (#23209) 2026-04-17 20:50:36 -04:00
Kit Langton 05cdb7c107 refactor(v2): tag session unions and exhaustively match events (#23201) 2026-04-18 00:29:26 +00:00
Kit Langton b493dabfe6 docs(effect): refresh migration status specs (#23206) 2026-04-18 00:29:26 +00:00
opencode-agent[bot] c4816f944e chore: generate 2026-04-18 00:29:26 +00:00
Kit Langton 211136e3a8 feat(effect-zod): transform support + walk memoization + flattened checks (#23203) 2026-04-18 00:29:26 +00:00
opencode-agent[bot] cf0a53c501 chore: generate 2026-04-18 00:29:26 +00:00
Kit Langton 2899984819 refactor(config): migrate provider (Model + Info) to Effect Schema (#23197) 2026-04-18 00:29:26 +00:00
Kit Langton eafbe5c57c refactor(server): align route-span attrs with OTel semantic conventions (#23198) 2026-04-18 00:29:26 +00:00
Kit Langton 7b98f544ff feat(effect-zod): add catchall (StructWithRest) support to the walker (#23186) 2026-04-18 00:29:26 +00:00
Kit Langton b5aba5807c feat(tui): show session ID in sidebar on non-prod channels (#23185) 2026-04-18 00:29:26 +00:00
Kit Langton 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
Dax cded68a2e2 refactor(npm): use object-based package spec for install API (#23181) 2026-04-17 17:30:50 -04:00
Aiden Cline 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 Langton 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 Langton ce69bd97b9 refactor(config): migrate model-id and command to Effect Schema (#23175) 2026-04-17 20:59:24 +00:00
Kit Langton 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 Langton 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 Langton 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 Long 47f553f9ba fix(core): more explicit routing to fix workspace instance issue (#23171) 2026-04-17 16:39:34 -04:00
Kit Langton d11268ece7 refactor(config): migrate permission Action/Object/Rule leaves to Effect Schema (#23168) 2026-04-17 20:35:42 +00:00
Kit Langton 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 Langton 11fa257549 refactor(config): migrate mcp schemas to Effect Schema.Class (#23163) 2026-04-17 20:25:49 +00:00
Kit Langton 6af8ab0df2 docs(http-api): refresh bridge inventory and clarify Schema.Class vs Struct (#23164) 2026-04-17 16:20:57 -04:00
Kit Langton 984f5ed6eb fix(opencode): skip share sync for unshared sessions (#23159) 2026-04-17 20:15:24 +00:00
opencode-agent[bot] c2061c6bbf chore: generate 2026-04-17 20:13:34 +00:00
Dax 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 Langton f83cecaaf6 fix(opencode): untrace streaming event hot paths (#23156) 2026-04-17 15:29:32 -04:00
James Long aa05b9abe5 fix(core): pass OTEL config to workspace env (#23154) 2026-04-17 15:25:58 -04:00
Kit Langton 68834cfcc3 fix(opencode): normalize provider metadata and tag otel runs (#23140) 2026-04-17 15:22:08 -04:00
James Long 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 Long b275b8580d feat(tui): minor UX improvements for workspaces (#23146) 2026-04-17 15:14:05 -04:00
Dax 467be08e67 refactor: consolidate npm exports and trace flock acquisition (#23151) 2026-04-17 18:58:37 +00:00
Aiden Cline 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 Long 4c30a78cd9 fix: revert sdk generation script change (#23133) 2026-04-17 13:33:11 -04:00
James Long 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 Long 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 Langton 13dfe569ef tui: fix agent cycling and prompt metadata polish (#23115) 2026-04-17 12:45:29 -04:00
Aiden Cline 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 Glafirov 0d582f9d3f chore: bump gitlab-ai-provider to 6.6.0 (#23057) 2026-04-17 11:22:43 -05:00
Dax Raad 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 Person 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
OpeOginni 8fbbca5f4b fix(opencode): rescrict github copilot opus 4.7 variants to "medium" (#23097) 2026-04-17 10:25:12 -05:00
Brendan Allan 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 Long 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
Sebastian 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 Allan a726530735 fix(app): workspace loading and persist ready state (#23046) 2026-04-17 07:26:14 +00:00
Dax 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
Dax 65b2a10e97 fade in prompt metadata transitions (#23037) 2026-04-17 06:12:41 +00:00
James Long 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 Long 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 Cline 76a141090e chore: delete filetime module (#22999) 2026-04-16 23:31:21 -05:00
Dax 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 Allan 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 Langton 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 Langton 4260c40efa refactor(tui): inline final Go shimmer settings (#23017) 2026-04-17 03:36:21 +00:00
James Long 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 Langton cccb907a9b feat(tui): animated GO logo + radial pulse in free-limit upsell dialog (#22976) 2026-04-16 23:19:18 -04:00
Kit Langton ee7339f2c6 refactor: move provider and config provider routes onto HttpApi (#23004) 2026-04-16 23:10:45 -04:00
Kit Langton 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
Dax 220e3e9a2b refactor: make formatter config opt-in (#22997) 2026-04-17 02:33:09 +00:00
Brendan Allan 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
Dax ee708040f6 fix: prefer real undo filenames over /dev/null (#23006) 2026-04-16 22:25:43 -04:00
Kit Langton 61c4815a37 refactor: unwrap FileWatcher namespace + self-reexport (redo) (#23000) 2026-04-17 02:20:43 +00:00
Dax 01bb54a94d refactor: split config parsing steps (#22996) 2026-04-17 01:57:43 +00:00
Kit Langton f592c3846b refactor: convert Flag namespace to const object with getters (#22984) 2026-04-17 01:57:21 +00:00
Kit Langton c026e25088 refactor: eliminate account/ barrel, route consumers to sibling files (#22995) 2026-04-17 01:55:50 +00:00
Kit Langton 8ba73bed23 refactor: collapse auth/ barrel — merge auth.ts into index.ts + self-reexport (#22993) 2026-04-17 01:52:19 +00:00
Kit Langton 4f8986aa48 refactor: unwrap Question namespace + fix script to emit "." for index.ts (#22992) 2026-04-17 01:51:02 +00:00
Kit Langton 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
Dax f13778215a perf: speed up skill directory discovery (#22990) 2026-04-17 01:35:47 +00:00
Dax 326471a25c refactor: split config lsp and formatter schemas (#22986) 2026-04-17 01:35:26 +00:00
Dax 6405e3a7b1 tui: stabilize session dialog ordering (#22987) 2026-04-17 01:32:36 +00:00
Kit Langton 8afb625bab refactor: extract Diagnostic namespace into lsp/diagnostic.ts + self-reexport (#22983) 2026-04-17 01:19:01 +00:00
Kit Langton c59df636cc chore: delete empty v2/session-common + collapse patch barrel (#22981) 2026-04-17 01:02:09 +00:00
Kit Langton 94878d76f8 refactor: unwrap TuiPluginRuntime namespace + self-reexport (#22980) 2026-04-17 01:02:07 +00:00
Kit Langton 5022895e2b refactor: unwrap ExperimentalHttpApiServer namespace + self-reexport (#22979) 2026-04-17 01:01:24 +00:00
Kit Langton 54046e0b98 refactor: unwrap SessionV2 namespace + self-reexport (#22978) 2026-04-17 01:00:30 +00:00
Kit Langton 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 Langton 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 Langton 54078c4cae refactor: unwrap Shell namespace + self-reexport (#22964) 2026-04-16 20:11:19 -04:00
Kit Langton 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 Langton 635970b0a1 refactor: unwrap ConfigSkills namespace + self-reexport (#22950) 2026-04-17 00:02:53 +00:00
Kit Langton 059b32c212 refactor: unwrap Protected namespace + self-reexport (#22938) 2026-04-17 00:02:51 +00:00
Kit Langton 2704ad9110 refactor: unwrap TuiConfig namespace + self-reexport (#22952) 2026-04-17 00:02:24 +00:00
Kit Langton 06d247c709 refactor: unwrap FileIgnore namespace + self-reexport (#22937) 2026-04-17 00:02:08 +00:00
Kit Langton 974fa1b8b1 refactor: unwrap PluginMeta namespace + self-reexport (#22945) 2026-04-17 00:02:05 +00:00
Kit Langton fb02744460 refactor: unwrap Agent namespace + self-reexport (#22935) 2026-04-17 00:01:44 +00:00
Kit Langton 79732ab175 refactor: unwrap UI namespace + self-reexport (#22951) 2026-04-17 00:01:41 +00:00
Kit Langton f6dbb2f3e0 refactor: unwrap Heap namespace + self-reexport (#22931) 2026-04-17 00:01:37 +00:00
Kit Langton fdd5b77bfd refactor: unwrap McpAuth namespace + self-reexport (#22942) 2026-04-17 00:01:12 +00:00
Kit Langton cde105e7a8 refactor: unwrap CopilotModels namespace + self-reexport (#22947) 2026-04-17 00:01:09 +00:00
Kit Langton 1291e82bb4 refactor: unwrap ACP namespace + self-reexport (#22936) 2026-04-17 00:00:50 +00:00
Kit Langton 19d15d9ff7 refactor: unwrap ConfigProvider namespace + self-reexport (#22949) 2026-04-17 00:00:48 +00:00
Kit Langton 4e27804160 refactor: unwrap McpOAuthCallback namespace + self-reexport (#22943) 2026-04-17 00:00:46 +00:00
Kit Langton 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 Langton 5d47ea0918 refactor: unwrap ConfigMCP namespace + self-reexport (#22948) 2026-04-16 19:52:04 -04:00
Kit Langton c03fa36257 refactor: unwrap Server namespace + self-reexport (#22970) 2026-04-16 23:51:01 +00:00
Kit Langton 1089fa0415 refactor: unwrap ServerProxy namespace + self-reexport (#22969) 2026-04-16 23:50:32 +00:00
Kit Langton 715786bbf9 refactor: unwrap FileTime namespace + self-reexport (#22966) 2026-04-16 23:50:15 +00:00
Kit Langton 218eca7c2b refactor: unwrap MDNS namespace + self-reexport (#22968) 2026-04-16 23:50:11 +00:00
Kit Langton 30fc791480 refactor: unwrap Ripgrep namespace + self-reexport (#22965) 2026-04-16 19:49:52 -04:00
Kit Langton e2d161dfdd refactor: unwrap Identifier namespace + self-reexport (#22963) 2026-04-16 23:48:24 +00:00
Kit Langton 23d48a7cf1 refactor: unwrap BusEvent namespace + self-reexport (#22962) 2026-04-16 23:46:49 +00:00
Aiden Cline 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 Langton 0e86466f99 refactor: unwrap Discovery namespace to flat exports + self-reexport (#22878) 2026-04-16 16:59:30 -04:00
Kit Langton 32548bcb4a refactor: unwrap ConfigPlugin namespace to flat exports + self-reexport (#22876) 2026-04-16 16:59:17 -04:00
James Long 86c54c5acc fix(tui): minor logging cleanup (#22924) 2026-04-16 16:58:17 -04:00
Aiden Cline ae584332b3 fix: uncomment import (#22923) 2026-04-16 15:56:29 -05:00
Kit Langton 1694c5bfe1 refactor: collapse file barrel into file/index.ts (#22901) 2026-04-16 16:56:09 -04:00
Kit Langton cdfbb26c00 refactor: collapse bus barrel into bus/index.ts (#22902) 2026-04-16 16:55:57 -04:00
thakrarsagaropencode-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 Langton 2638e2acfa refactor: collapse plugin barrel into plugin/index.ts (#22914) 2026-04-16 20:37:13 +00:00
Kit Langton 49bbea5aed refactor: collapse snapshot barrel into snapshot/index.ts (#22916) 2026-04-16 20:36:45 +00:00
Kit Langton 5fccdc9fc7 refactor: collapse mcp barrel into mcp/index.ts (#22913) 2026-04-16 20:36:23 +00:00
Kit Langton 664b2c36e8 refactor: collapse git barrel into git/index.ts (#22909) 2026-04-16 20:36:07 +00:00
Kit Langton 964474a1b1 refactor: collapse permission barrel into permission/index.ts (#22915) 2026-04-16 20:36:04 +00:00
Kit Langton ab15fc1575 refactor: collapse npm barrel into npm/index.ts (#22911) 2026-04-16 20:36:02 +00:00
Kit Langton 99d392a4fb refactor: collapse skill barrel into skill/index.ts (#22912) 2026-04-16 20:35:43 +00:00
Kit Langton ae9a696607 refactor: collapse installation barrel into installation/index.ts (#22910) 2026-04-16 20:35:28 +00:00
Kit Langton bd51a0d35b refactor: collapse worktree barrel into worktree/index.ts (#22906) 2026-04-16 20:35:26 +00:00
Kit Langton 8c191b10c2 refactor: collapse ide barrel into ide/index.ts (#22904) 2026-04-16 20:35:04 +00:00
Kit Langton cb6a9253fe refactor: collapse sync barrel into sync/index.ts (#22907) 2026-04-16 20:34:33 +00:00
Kit Langton 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 Langton 3fe906f517 refactor: collapse command barrel into command/index.ts (#22903) 2026-04-16 20:30:52 +00:00
James Long a8d8a35cd3 feat(core): pass auth data to workspace (#22897) 2026-04-16 16:30:11 -04:00
Kit Langton 9b77430d0d refactor: collapse env barrel into env/index.ts (#22900) 2026-04-16 16:29:54 -04:00
Kit Langton 1045a43603 refactor: collapse format barrel into format/index.ts (#22898) 2026-04-16 16:29:51 -04:00
James Long 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 Langton e0d71f124e tooling: add collapse-barrel.ts for single-namespace barrel migration (#22887) 2026-04-16 16:12:46 -04:00
Kit Langton 1c33b866ba fix: remove 10 more unnecessary as any casts in opencode core (#22882) 2026-04-16 20:11:05 +00:00
Kobi HudsonandAiden Cline 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 Langton 76275fc3ab refactor: move Pty into pty/index.ts with self-reexport (#22881) 2026-04-16 15:49:21 -04:00
Aiden Cline 6c3b28db64 fix: ensure that double pasting doesnt happen after tui perf commit was merged (#22880) 2026-04-16 14:38:39 -05:00
Kit Langton 2fe9d94470 fix: remove 8 more unnecessary as any casts in opencode core (#22877) 2026-04-16 19:27:53 +00:00
Kit Langton 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 Cline 47e0e2342c tweak: set display 'summarized' by default for opus 4.7 thorugh messages api (#22873) 2026-04-16 14:12:43 -05:00
Kit Langton bf4c107829 fix: remove 7 unnecessary as any casts in opencode core (#22840) 2026-04-16 15:07:02 -04:00
Dax 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 Cline 143817d44e chore: bump ai sdk deps for opus 4.7 (#22869) 2026-04-16 13:28:20 -05:00
Thomas Butler 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 Cline 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 Long 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 Long 06afd33291 refactor(tui): improve workspace management (#22691) 2026-04-16 12:24:40 -04:00
James Long 305460b25f fix: add a few more tests for sync and session restore (#22837) 2026-04-16 12:15:44 -04:00
Nacaiopencode-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
Graham CampbellandAiden Cline 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 Benoit 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
Dax ef90b93205 fix: restore .gitignore logic for config dirs and migrate to shared Npm service (#22772) 2026-04-16 03:14:06 -04:00
Dax 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 Allan 97918500d4 app: start migrating bootstrap data fetching to TanStack Query (#22756) 2026-04-16 06:10:23 +00:00
Brendan Allan e2c0803962 Fix desktop download asset names for beta channel (#22766) 2026-04-16 06:10:03 +00:00
AdamandBrendan Allan f418fd5632 beta badge for desktop app (#14471)
Co-authored-by: Brendan Allan <git@brendonovich.dev>
2026-04-16 06:03:41 +00:00
Dax 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 Langton 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 Langton 5011465c81 feat: unwrap tool namespaces to flat exports + barrel (#22762) 2026-04-16 03:56:54 +00:00
Kit Langton f6cc228684 feat: unwrap cli-tui namespaces to flat exports + barrel (#22759) 2026-04-16 03:56:51 +00:00
Kit Langton 9f4b73b6a3 fix: clean up final 16 no-unused-vars warnings (#22751) 2026-04-16 03:54:21 +00:00
Kit Langton bd29004831 feat: enable type-aware no-misused-spread rule, fix 8 violations (#22749) 2026-04-16 03:50:50 +00:00
Kit Langton 8aa0f9fe95 feat: enable type-aware no-base-to-string rule, fix 56 violations (#22750) 2026-04-16 03:50:47 +00:00
Kit Langton 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 Langton 0e20382396 fix: resolve circular sibling imports causing runtime ReferenceError (#22752) 2026-04-15 23:41:34 -04:00
Kit Langton 509bc11f81 feat: unwrap lsp namespaces to flat exports + barrel (#22748) 2026-04-15 23:30:52 -04:00
Kit Langton f24207844f feat: unwrap storage namespaces to flat exports + barrel (#22747) 2026-04-15 23:30:49 -04:00
Kit Langton 1ca257e356 feat: unwrap config namespaces to flat exports + barrel (#22746) 2026-04-15 23:29:14 -04:00
Kit Langton d4cfbd020d feat: unwrap effect namespaces to flat exports + barrel (#22745) 2026-04-15 23:29:12 -04:00
Kit Langton 581d5208ca feat: unwrap share namespaces to flat exports + barrel (#22744) 2026-04-15 23:28:46 -04:00
Kit Langton 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 Langton 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 Langton 343a564183 feat: unwrap 11 util namespaces to flat exports + barrel (#22739) 2026-04-15 23:15:58 -04:00
Kit Langton b0eae5e12f feat: bridge permission and provider auth routes behind OPENCODE_EXPERIMENTAL_HTTPAPI (#22736) 2026-04-15 23:02:48 -04:00
Kit Langton 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 Langton 665a843086 feat: unwrap Archive namespace to flat exports + barrel (#22722) 2026-04-16 02:52:34 +00:00
Kit Langton 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 Langton 379e40d772 feat: unwrap InstanceState + EffectBridge namespaces to flat exports + barrel (#22721) 2026-04-16 02:45:45 +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
986 changed files with 82641 additions and 42787 deletions
+1
View File
@@ -13,3 +13,4 @@ R44VC0RP
rekram1-node rekram1-node
RhysSullivan RhysSullivan
thdxr thdxr
simonklee
+4
View File
@@ -12,8 +12,10 @@ adamdotdevin
ariane-emory ariane-emory
-atharvau AI review spamming literally every PR -atharvau AI review spamming literally every PR
-borealbytes -borealbytes
-carycooper777
-danieljoshuanazareth -danieljoshuanazareth
-danieljoshuanazareth -danieljoshuanazareth
-davidbernat looks to be a clawdbot that spams team and sends super weird emails, doesnt appear to be a real person
edemaine edemaine
-florianleibert -florianleibert
fwang fwang
@@ -27,8 +29,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
-terisuke
thdxr thdxr
-toastythebot -toastythebot
+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 }}
-900
View File
@@ -1,900 +0,0 @@
---
description: Translate content for a specified locale while preserving technical terms
mode: subagent
model: opencode/gpt-5.4
---
You are a professional translator and localization specialist.
Translate the user's content into the requested target locale (language + region, e.g. fr-FR, de-DE).
Requirements:
- Preserve meaning, intent, tone, and formatting (including Markdown/MDX structure).
- Preserve all technical terms and artifacts exactly: product/company names, API names, identifiers, code, commands/flags, file paths, URLs, versions, error messages, config keys/values, and anything inside inline code or code blocks.
- Also preserve every term listed in the Do-Not-Translate glossary below.
- Also apply locale-specific guidance from `.opencode/glossary/<locale>.md` when available (for example, `zh-cn.md`).
- Do not modify fenced code blocks.
- Output ONLY the translation (no commentary).
If the target locale is missing, ask the user to provide it.
If no locale-specific glossary exists, use the global glossary only.
---
# Locale-Specific Glossaries
When a locale glossary exists, use it to:
- Apply preferred wording for recurring UI/docs terms in that locale
- Preserve locale-specific do-not-translate terms and casing decisions
- Prefer natural phrasing over literal translation when the locale file calls it out
- If the repo uses a locale alias slug, apply that file too (for example, `pt-BR` maps to `br.md` in this repo)
Locale guidance does not override code/command preservation rules or the global Do-Not-Translate glossary below.
---
# Do-Not-Translate Terms (OpenCode Docs)
Generated from: `packages/web/src/content/docs/*.mdx` (default English docs)
Generated on: 2026-02-10
Use this as a translation QA checklist / glossary. Preserve listed terms exactly (spelling, casing, punctuation).
General rules (verbatim, even if not listed below):
- Anything inside inline code (single backticks) or fenced code blocks (triple backticks)
- MDX/JS code in docs: `import ... from "..."`, component tags, identifiers
- CLI commands, flags, config keys/values, file paths, URLs/domains, and env vars
## Proper nouns and product names
Additional (not reliably captured via link text):
```text
Astro
Bun
Chocolatey
Cursor
Docker
Git
GitHub Actions
GitLab CI
GNOME Terminal
Homebrew
Mise
Neovim
Node.js
npm
Obsidian
opencode
opencode-ai
Paru
pnpm
ripgrep
Scoop
SST
Starlight
Visual Studio Code
VS Code
VSCodium
Windsurf
Windows Terminal
Yarn
Zellij
Zed
anomalyco
```
Extracted from link labels in the English docs (review and prune as desired):
```text
@openspoon/subtask2
302.AI console
ACP progress report
Agent Client Protocol
Agent Skills
Agentic
AGENTS.md
AI SDK
Alacritty
Anthropic
Anthropic's Data Policies
Atom One
Avante.nvim
Ayu
Azure AI Foundry
Azure portal
Baseten
built-in GITHUB_TOKEN
Bun.$
Catppuccin
Cerebras console
ChatGPT Plus or Pro
Cloudflare dashboard
CodeCompanion.nvim
CodeNomad
Configuring Adapters: Environment Variables
Context7 MCP server
Cortecs console
Deep Infra dashboard
DeepSeek console
Duo Agent Platform
Everforest
Fireworks AI console
Firmware dashboard
Ghostty
GitLab CLI agents docs
GitLab docs
GitLab User Settings > Access Tokens
Granular Rules (Object Syntax)
Grep by Vercel
Groq console
Gruvbox
Helicone
Helicone documentation
Helicone Header Directory
Helicone's Model Directory
Hugging Face Inference Providers
Hugging Face settings
install WSL
IO.NET console
JetBrains IDE
Kanagawa
Kitty
MiniMax API Console
Models.dev
Moonshot AI console
Nebius Token Factory console
Nord
OAuth
Ollama integration docs
OpenAI's Data Policies
OpenChamber
OpenCode
OpenCode config
OpenCode Config
OpenCode TUI with the opencode theme
OpenCode Web - Active Session
OpenCode Web - New Session
OpenCode Web - See Servers
OpenCode Zen
OpenCode-Obsidian
OpenRouter dashboard
OpenWork
OVHcloud panel
Pro+ subscription
SAP BTP Cockpit
Scaleway Console IAM settings
Scaleway Generative APIs
SDK documentation
Sentry MCP server
shell API
Together AI console
Tokyonight
Unified Billing
Venice AI console
Vercel dashboard
WezTerm
Windows Subsystem for Linux (WSL)
WSL
WSL (Windows Subsystem for Linux)
WSL extension
xAI console
Z.AI API console
Zed
ZenMux dashboard
Zod
```
## Acronyms and initialisms
```text
ACP
AGENTS
AI
AI21
ANSI
API
AST
AWS
BTP
CD
CDN
CI
CLI
CMD
CORS
DEBUG
EKS
ERROR
FAQ
GLM
GNOME
GPT
HTML
HTTP
HTTPS
IAM
ID
IDE
INFO
IO
IP
IRSA
JS
JSON
JSONC
K2
LLM
LM
LSP
M2
MCP
MR
NET
NPM
NTLM
OIDC
OS
PAT
PATH
PHP
PR
PTY
README
RFC
RPC
SAP
SDK
SKILL
SSE
SSO
TS
TTY
TUI
UI
URL
US
UX
VCS
VPC
VPN
VS
WARN
WSL
X11
YAML
```
## Code identifiers used in prose (CamelCase, mixedCase)
```text
apiKey
AppleScript
AssistantMessage
baseURL
BurntSushi
ChatGPT
ClangFormat
CodeCompanion
CodeNomad
DeepSeek
DefaultV2
FileContent
FileDiff
FileNode
fineGrained
FormatterStatus
GitHub
GitLab
iTerm2
JavaScript
JetBrains
macOS
mDNS
MiniMax
NeuralNomadsAI
NickvanDyke
NoeFabris
OpenAI
OpenAPI
OpenChamber
OpenCode
OpenRouter
OpenTUI
OpenWork
ownUserPermissions
PowerShell
ProviderAuthAuthorization
ProviderAuthMethod
ProviderInitError
SessionStatus
TabItem
tokenType
ToolIDs
ToolList
TypeScript
typesUrl
UserMessage
VcsInfo
WebView2
WezTerm
xAI
ZenMux
```
## OpenCode CLI commands (as shown in docs)
```text
opencode
opencode [project]
opencode /path/to/project
opencode acp
opencode agent [command]
opencode agent create
opencode agent list
opencode attach [url]
opencode attach http://10.20.30.40:4096
opencode attach http://localhost:4096
opencode auth [command]
opencode auth list
opencode auth login
opencode auth logout
opencode auth ls
opencode export [sessionID]
opencode github [command]
opencode github install
opencode github run
opencode import <file>
opencode import https://opncd.ai/s/abc123
opencode import session.json
opencode mcp [command]
opencode mcp add
opencode mcp auth [name]
opencode mcp auth list
opencode mcp auth ls
opencode mcp auth my-oauth-server
opencode mcp auth sentry
opencode mcp debug <name>
opencode mcp debug my-oauth-server
opencode mcp list
opencode mcp logout [name]
opencode mcp logout my-oauth-server
opencode mcp ls
opencode models --refresh
opencode models [provider]
opencode models anthropic
opencode run [message..]
opencode run Explain the use of context in Go
opencode serve
opencode serve --cors http://localhost:5173 --cors https://app.example.com
opencode serve --hostname 0.0.0.0 --port 4096
opencode serve [--port <number>] [--hostname <string>] [--cors <origin>]
opencode session [command]
opencode session list
opencode session delete <sessionID>
opencode stats
opencode uninstall
opencode upgrade
opencode upgrade [target]
opencode upgrade v0.1.48
opencode web
opencode web --cors https://example.com
opencode web --hostname 0.0.0.0
opencode web --mdns
opencode web --mdns --mdns-domain myproject.local
opencode web --port 4096
opencode web --port 4096 --hostname 0.0.0.0
opencode.server.close()
```
## Slash commands and routes
```text
/agent
/auth/:id
/clear
/command
/config
/config/providers
/connect
/continue
/doc
/editor
/event
/experimental/tool?provider=<p>&model=<m>
/experimental/tool/ids
/export
/file?path=<path>
/file/content?path=<p>
/file/status
/find?pattern=<pat>
/find/file
/find/file?query=<q>
/find/symbol?query=<q>
/formatter
/global/event
/global/health
/help
/init
/instance/dispose
/log
/lsp
/mcp
/mnt/
/mnt/c/
/mnt/d/
/models
/oc
/opencode
/path
/project
/project/current
/provider
/provider/{id}/oauth/authorize
/provider/{id}/oauth/callback
/provider/auth
/q
/quit
/redo
/resume
/session
/session/:id
/session/:id/abort
/session/:id/children
/session/:id/command
/session/:id/diff
/session/:id/fork
/session/:id/init
/session/:id/message
/session/:id/message/:messageID
/session/:id/permissions/:permissionID
/session/:id/prompt_async
/session/:id/revert
/session/:id/share
/session/:id/shell
/session/:id/summarize
/session/:id/todo
/session/:id/unrevert
/session/status
/share
/summarize
/theme
/tui
/tui/append-prompt
/tui/clear-prompt
/tui/control/next
/tui/control/response
/tui/execute-command
/tui/open-help
/tui/open-models
/tui/open-sessions
/tui/open-themes
/tui/show-toast
/tui/submit-prompt
/undo
/Users/username
/Users/username/projects/*
/vcs
```
## CLI flags and short options
```text
--agent
--attach
--command
--continue
--cors
--cwd
--days
--dir
--dry-run
--event
--file
--force
--fork
--format
--help
--hostname
--hostname 0.0.0.0
--keep-config
--keep-data
--log-level
--max-count
--mdns
--mdns-domain
--method
--model
--models
--port
--print-logs
--project
--prompt
--refresh
--session
--share
--title
--token
--tools
--verbose
--version
--wait
-c
-d
-f
-h
-m
-n
-s
-v
```
## Environment variables
```text
AI_API_URL
AI_FLOW_CONTEXT
AI_FLOW_EVENT
AI_FLOW_INPUT
AICORE_DEPLOYMENT_ID
AICORE_RESOURCE_GROUP
AICORE_SERVICE_KEY
ANTHROPIC_API_KEY
AWS_ACCESS_KEY_ID
AWS_BEARER_TOKEN_BEDROCK
AWS_PROFILE
AWS_REGION
AWS_ROLE_ARN
AWS_SECRET_ACCESS_KEY
AWS_WEB_IDENTITY_TOKEN_FILE
AZURE_COGNITIVE_SERVICES_RESOURCE_NAME
AZURE_RESOURCE_NAME
CI_PROJECT_DIR
CI_SERVER_FQDN
CI_WORKLOAD_REF
CLOUDFLARE_ACCOUNT_ID
CLOUDFLARE_API_TOKEN
CLOUDFLARE_GATEWAY_ID
CONTEXT7_API_KEY
GITHUB_TOKEN
GITLAB_AI_GATEWAY_URL
GITLAB_HOST
GITLAB_INSTANCE_URL
GITLAB_OAUTH_CLIENT_ID
GITLAB_TOKEN
GITLAB_TOKEN_OPENCODE
GOOGLE_APPLICATION_CREDENTIALS
GOOGLE_CLOUD_PROJECT
HTTP_PROXY
HTTPS_PROXY
K2_
MY_API_KEY
MY_ENV_VAR
MY_MCP_CLIENT_ID
MY_MCP_CLIENT_SECRET
NO_PROXY
NODE_ENV
NODE_EXTRA_CA_CERTS
NPM_AUTH_TOKEN
OC_ALLOW_WAYLAND
OPENCODE_API_KEY
OPENCODE_AUTH_JSON
OPENCODE_AUTO_SHARE
OPENCODE_CLIENT
OPENCODE_CONFIG
OPENCODE_CONFIG_CONTENT
OPENCODE_CONFIG_DIR
OPENCODE_DISABLE_AUTOCOMPACT
OPENCODE_DISABLE_AUTOUPDATE
OPENCODE_DISABLE_CLAUDE_CODE
OPENCODE_DISABLE_CLAUDE_CODE_PROMPT
OPENCODE_DISABLE_CLAUDE_CODE_SKILLS
OPENCODE_DISABLE_DEFAULT_PLUGINS
OPENCODE_DISABLE_FILETIME_CHECK
OPENCODE_DISABLE_LSP_DOWNLOAD
OPENCODE_DISABLE_MODELS_FETCH
OPENCODE_DISABLE_PRUNE
OPENCODE_DISABLE_TERMINAL_TITLE
OPENCODE_ENABLE_EXA
OPENCODE_ENABLE_EXPERIMENTAL_MODELS
OPENCODE_EXPERIMENTAL
OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS
OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT
OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER
OPENCODE_EXPERIMENTAL_EXA
OPENCODE_EXPERIMENTAL_FILEWATCHER
OPENCODE_EXPERIMENTAL_ICON_DISCOVERY
OPENCODE_EXPERIMENTAL_LSP_TOOL
OPENCODE_EXPERIMENTAL_LSP_TY
OPENCODE_EXPERIMENTAL_MARKDOWN
OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX
OPENCODE_EXPERIMENTAL_OXFMT
OPENCODE_EXPERIMENTAL_PLAN_MODE
OPENCODE_ENABLE_QUESTION_TOOL
OPENCODE_FAKE_VCS
OPENCODE_GIT_BASH_PATH
OPENCODE_MODEL
OPENCODE_MODELS_URL
OPENCODE_PERMISSION
OPENCODE_PORT
OPENCODE_SERVER_PASSWORD
OPENCODE_SERVER_USERNAME
PROJECT_ROOT
RESOURCE_NAME
RUST_LOG
VARIABLE_NAME
VERTEX_LOCATION
XDG_CONFIG_HOME
```
## Package/module identifiers
```text
../../../config.mjs
@astrojs/starlight/components
@opencode-ai/plugin
@opencode-ai/sdk
path
shescape
zod
@
@ai-sdk/anthropic
@ai-sdk/cerebras
@ai-sdk/google
@ai-sdk/openai
@ai-sdk/openai-compatible
@File#L37-42
@modelcontextprotocol/server-everything
@opencode
```
## GitHub owner/repo slugs referenced in docs
```text
24601/opencode-zellij-namer
angristan/opencode-wakatime
anomalyco/opencode
apps/opencode-agent
athal7/opencode-devcontainers
awesome-opencode/awesome-opencode
backnotprop/plannotator
ben-vargas/ai-sdk-provider-opencode-sdk
btriapitsyn/openchamber
BurntSushi/ripgrep
Cluster444/agentic
code-yeongyu/oh-my-opencode
darrenhinde/opencode-agents
different-ai/opencode-scheduler
different-ai/openwork
features/copilot
folke/tokyonight.nvim
franlol/opencode-md-table-formatter
ggml-org/llama.cpp
ghoulr/opencode-websearch-cited.git
H2Shami/opencode-helicone-session
hosenur/portal
jamesmurdza/daytona
jenslys/opencode-gemini-auth
JRedeker/opencode-morph-fast-apply
JRedeker/opencode-shell-strategy
kdcokenny/ocx
kdcokenny/opencode-background-agents
kdcokenny/opencode-notify
kdcokenny/opencode-workspace
kdcokenny/opencode-worktree
login/device
mohak34/opencode-notifier
morhetz/gruvbox
mtymek/opencode-obsidian
NeuralNomadsAI/CodeNomad
nick-vi/opencode-type-inject
NickvanDyke/opencode.nvim
NoeFabris/opencode-antigravity-auth
nordtheme/nord
numman-ali/opencode-openai-codex-auth
olimorris/codecompanion.nvim
panta82/opencode-notificator
rebelot/kanagawa.nvim
remorses/kimaki
sainnhe/everforest
shekohex/opencode-google-antigravity-auth
shekohex/opencode-pty.git
spoons-and-mirrors/subtask2
sudo-tee/opencode.nvim
supermemoryai/opencode-supermemory
Tarquinen/opencode-dynamic-context-pruning
Th3Whit3Wolf/one-nvim
upstash/context7
vtemian/micode
vtemian/octto
yetone/avante.nvim
zenobi-us/opencode-plugin-template
zenobi-us/opencode-skillful
```
## Paths, filenames, globs, and URLs
```text
./.opencode/themes/*.json
./<project-slug>/storage/
./config/#custom-directory
./global/storage/
.agents/skills/*/SKILL.md
.agents/skills/<name>/SKILL.md
.clang-format
.claude
.claude/skills
.claude/skills/*/SKILL.md
.claude/skills/<name>/SKILL.md
.env
.github/workflows/opencode.yml
.gitignore
.gitlab-ci.yml
.ignore
.NET SDK
.npmrc
.ocamlformat
.opencode
.opencode/
.opencode/agents/
.opencode/commands/
.opencode/commands/test.md
.opencode/modes/
.opencode/plans/*.md
.opencode/plugins/
.opencode/skills/<name>/SKILL.md
.opencode/skills/git-release/SKILL.md
.opencode/tools/
.well-known/opencode
{ type: "raw" \| "patch", content: string }
{file:path/to/file}
**/*.js
%USERPROFILE%/intelephense/license.txt
%USERPROFILE%\.cache\opencode
%USERPROFILE%\.config\opencode\opencode.jsonc
%USERPROFILE%\.config\opencode\plugins
%USERPROFILE%\.local\share\opencode
%USERPROFILE%\.local\share\opencode\log
<project-root>/.opencode/themes/*.json
<providerId>/<modelId>
<your-project>/.opencode/plugins/
~
~/...
~/.agents/skills/*/SKILL.md
~/.agents/skills/<name>/SKILL.md
~/.aws/credentials
~/.bashrc
~/.cache/opencode
~/.cache/opencode/node_modules/
~/.claude/CLAUDE.md
~/.claude/skills/
~/.claude/skills/*/SKILL.md
~/.claude/skills/<name>/SKILL.md
~/.config/opencode
~/.config/opencode/AGENTS.md
~/.config/opencode/agents/
~/.config/opencode/commands/
~/.config/opencode/modes/
~/.config/opencode/opencode.json
~/.config/opencode/opencode.jsonc
~/.config/opencode/plugins/
~/.config/opencode/skills/*/SKILL.md
~/.config/opencode/skills/<name>/SKILL.md
~/.config/opencode/themes/*.json
~/.config/opencode/tools/
~/.config/zed/settings.json
~/.local/share
~/.local/share/opencode/
~/.local/share/opencode/auth.json
~/.local/share/opencode/log/
~/.local/share/opencode/mcp-auth.json
~/.local/share/opencode/opencode.jsonc
~/.npmrc
~/.zshrc
~/code/
~/Library/Application Support
~/projects/*
~/projects/personal/
${config.github}/blob/dev/packages/sdk/js/src/gen/types.gen.ts
$HOME/intelephense/license.txt
$HOME/projects/*
$XDG_CONFIG_HOME/opencode/themes/*.json
agent/
agents/
build/
commands/
dist/
http://<wsl-ip>:4096
http://127.0.0.1:8080/callback
http://localhost:<port>
http://localhost:4096
http://localhost:4096/doc
https://app.example.com
https://AZURE_COGNITIVE_SERVICES_RESOURCE_NAME.cognitiveservices.azure.com/
https://opencode.ai/zen/v1/chat/completions
https://opencode.ai/zen/v1/messages
https://opencode.ai/zen/v1/models/gemini-3-flash
https://opencode.ai/zen/v1/models/gemini-3-pro
https://opencode.ai/zen/v1/responses
https://RESOURCE_NAME.openai.azure.com/
laravel/pint
log/
model: "anthropic/claude-sonnet-4-5"
modes/
node_modules/
openai/gpt-4.1
opencode.ai/config.json
opencode/<model-id>
opencode/gpt-5.1-codex
opencode/gpt-5.2-codex
opencode/kimi-k2
openrouter/google/gemini-2.5-flash
opncd.ai/s/<share-id>
packages/*/AGENTS.md
plugins/
project/
provider_id/model_id
provider/model
provider/model-id
rm -rf ~/.cache/opencode
skills/
skills/*/SKILL.md
src/**/*.ts
themes/
tools/
```
## Keybind strings
```text
alt+b
Alt+Ctrl+K
alt+d
alt+f
Cmd+Esc
Cmd+Option+K
Cmd+Shift+Esc
Cmd+Shift+G
Cmd+Shift+P
ctrl+a
ctrl+b
ctrl+d
ctrl+e
Ctrl+Esc
ctrl+f
ctrl+g
ctrl+k
Ctrl+Shift+Esc
Ctrl+Shift+P
ctrl+t
ctrl+u
ctrl+w
ctrl+x
DELETE
Shift+Enter
WIN+R
```
## Model ID strings referenced
```text
{env:OPENCODE_MODEL}
anthropic/claude-3-5-sonnet-20241022
anthropic/claude-haiku-4-20250514
anthropic/claude-haiku-4-5
anthropic/claude-sonnet-4-20250514
anthropic/claude-sonnet-4-5
gitlab/duo-chat-haiku-4-5
lmstudio/google/gemma-3n-e4b
openai/gpt-4.1
openai/gpt-5
opencode/gpt-5.1-codex
opencode/gpt-5.2-codex
opencode/kimi-k2
openrouter/google/gemini-2.5-flash
```
+14
View File
@@ -0,0 +1,14 @@
---
description: translate English to other languages
model: opencode/claude-opus-4-7
---
run git diff and translate changed english doc and UI copy files to other international languages. Translate all languages in parallel to save time.
Requirements:
- Preserve meaning, intent, tone, and formatting (including Markdown/MDX structure).
- Preserve all technical terms and artifacts exactly: product/company names, API names, identifiers, code, commands/flags, file paths, URLs, versions, error messages, config keys/values, and anything inside inline code or code blocks.
- Also preserve every term listed in the Do-Not-Translate glossary below.
- Also apply locale-specific guidance from `.opencode/glossary/<locale>.md` when available (for example, `zh-cn.md`).
- Do not modify fenced code blocks.
+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",
+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) {
+3 -3
View File
@@ -3,8 +3,8 @@ import { tool } from "@opencode-ai/plugin"
const TEAM = { const TEAM = {
desktop: ["adamdotdevin", "iamdavidhill", "Brendonovich", "nexxeln"], desktop: ["adamdotdevin", "iamdavidhill", "Brendonovich", "nexxeln"],
zen: ["fwang", "MrMushrooooom"], zen: ["fwang", "MrMushrooooom"],
tui: ["thdxr", "kommander", "rekram1-node"], tui: ["kommander", "rekram1-node", "simonklee"],
core: ["thdxr", "rekram1-node", "jlongster"], core: ["kitlangton", "rekram1-node", "jlongster"],
docs: ["R44VC0RP"], docs: ["R44VC0RP"],
windows: ["Hona"], windows: ["Hona"],
} as const } as const
@@ -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) {
+37 -2
View File
@@ -1,6 +1,13 @@
{ {
"$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc-project.github.io/refs/heads/json-schema/src/public/.oxlintrc.schema.json", "$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": { "rules": {
"typescript/no-base-to-string": "warn",
// Effect uses `function*` with Effect.gen/Effect.fnUntraced that don't always yield // Effect uses `function*` with Effect.gen/Effect.fnUntraced that don't always yield
"require-yield": "off", "require-yield": "off",
// SolidJS uses `let ref: T | undefined` for JSX ref bindings assigned at runtime // SolidJS uses `let ref: T | undefined` for JSX ref bindings assigned at runtime
@@ -10,7 +17,35 @@
// Intentional control char matching (ANSI escapes, null byte sanitization) // Intentional control char matching (ANSI escapes, null byte sanitization)
"no-control-regex": "off", "no-control-regex": "off",
// SST and plugin tools require triple-slash references // SST and plugin tools require triple-slash references
"triple-slash-reference": "off" "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"
}, },
"ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts"] "options": {
"typeAware": true
},
"options": {
"typeAware": true
},
"ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts", "**/sdk.gen.ts"]
} }
+1
View File
@@ -14,6 +14,7 @@
- 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.
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.
+140 -93
View File
@@ -20,6 +20,7 @@
"glob": "13.0.5", "glob": "13.0.5",
"husky": "9.1.7", "husky": "9.1.7",
"oxlint": "1.60.0", "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",
@@ -28,11 +29,11 @@
}, },
"packages/app": { "packages/app": {
"name": "@opencode-ai/app", "name": "@opencode-ai/app",
"version": "1.4.6", "version": "1.14.28",
"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",
@@ -82,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.28",
"dependencies": { "dependencies": {
"@cloudflare/vite-plugin": "1.15.2", "@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1", "@ibm/plex": "6.4.1",
@@ -116,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.28",
"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",
@@ -143,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.28",
"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",
@@ -167,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.28",
"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",
@@ -189,9 +190,43 @@
"cloudflare": "5.2.0", "cloudflare": "5.2.0",
}, },
}, },
"packages/core": {
"name": "@opencode-ai/core",
"version": "1.14.28",
"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.28",
"dependencies": { "dependencies": {
"@opencode-ai/app": "workspace:*", "@opencode-ai/app": "workspace:*",
"@opencode-ai/ui": "workspace:*", "@opencode-ai/ui": "workspace:*",
@@ -224,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.28",
"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",
@@ -247,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:",
@@ -267,9 +303,9 @@
}, },
"packages/enterprise": { "packages/enterprise": {
"name": "@opencode-ai/enterprise", "name": "@opencode-ai/enterprise",
"version": "1.4.6", "version": "1.14.28",
"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:",
@@ -296,7 +332,7 @@
}, },
"packages/function": { "packages/function": {
"name": "@opencode-ai/function", "name": "@opencode-ai/function",
"version": "1.4.6", "version": "1.14.28",
"dependencies": { "dependencies": {
"@octokit/auth-app": "8.0.1", "@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:", "@octokit/rest": "catalog:",
@@ -312,7 +348,7 @@
}, },
"packages/opencode": { "packages/opencode": {
"name": "opencode", "name": "opencode",
"version": "1.4.6", "version": "1.14.28",
"bin": { "bin": {
"opencode": "./bin/opencode", "opencode": "./bin/opencode",
}, },
@@ -321,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",
@@ -351,21 +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:*",
"@openrouter/ai-sdk-provider": "2.5.1", "@openrouter/ai-sdk-provider": "2.8.1",
"@opentelemetry/api": "1.9.0", "@opentelemetry/api": "1.9.0",
"@opentelemetry/context-async-hooks": "2.6.1", "@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",
@@ -385,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",
@@ -400,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",
@@ -424,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",
@@ -441,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",
@@ -449,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",
@@ -457,23 +491,23 @@
}, },
"packages/plugin": { "packages/plugin": {
"name": "@opencode-ai/plugin", "name": "@opencode-ai/plugin",
"version": "1.4.6", "version": "1.14.28",
"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.105",
"@opentui/solid": ">=0.1.99", "@opentui/solid": ">=0.1.105",
}, },
"optionalPeers": [ "optionalPeers": [
"@opentui/core", "@opentui/core",
@@ -492,7 +526,7 @@
}, },
"packages/sdk/js": { "packages/sdk/js": {
"name": "@opencode-ai/sdk", "name": "@opencode-ai/sdk",
"version": "1.4.6", "version": "1.14.28",
"dependencies": { "dependencies": {
"cross-spawn": "catalog:", "cross-spawn": "catalog:",
}, },
@@ -505,30 +539,9 @@
"typescript": "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:",
"xdg-basedir": "5.1.0",
"zod": "catalog:",
},
"devDependencies": {
"@types/bun": "catalog:",
"@types/semver": "catalog:",
},
},
"packages/slack": { "packages/slack": {
"name": "@opencode-ai/slack", "name": "@opencode-ai/slack",
"version": "1.4.6", "version": "1.14.28",
"dependencies": { "dependencies": {
"@opencode-ai/sdk": "workspace:*", "@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1", "@slack/bolt": "^3.17.1",
@@ -563,11 +576,11 @@
}, },
"packages/ui": { "packages/ui": {
"name": "@opencode-ai/ui", "name": "@opencode-ai/ui",
"version": "1.4.6", "version": "1.14.28",
"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",
@@ -612,7 +625,7 @@
}, },
"packages/web": { "packages/web": {
"name": "@opencode-ai/web", "name": "@opencode-ai/web",
"version": "1.4.6", "version": "1.14.28",
"dependencies": { "dependencies": {
"@astrojs/cloudflare": "12.6.3", "@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1", "@astrojs/markdown-remark": "6.3.1",
@@ -656,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:",
@@ -663,14 +677,16 @@
}, },
"catalog": { "catalog": {
"@cloudflare/workers-types": "4.20251008.0", "@cloudflare/workers-types": "4.20251008.0",
"@effect/opentelemetry": "4.0.0-beta.48", "@effect/opentelemetry": "4.0.0-beta.57",
"@effect/platform-node": "4.0.0-beta.48", "@effect/platform-node": "4.0.0-beta.57",
"@hono/zod-validator": "0.4.2", "@hono/zod-validator": "0.4.2",
"@kobalte/core": "0.13.11", "@kobalte/core": "0.13.11",
"@lydell/node-pty": "1.2.0-beta.10", "@lydell/node-pty": "1.2.0-beta.10",
"@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.105",
"@opentui/solid": "0.1.105",
"@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",
@@ -680,25 +696,26 @@
"@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",
"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.57",
"fuzzysort": "3.1.0", "fuzzysort": "3.1.0",
"hono": "4.10.7", "hono": "4.10.7",
"hono-openapi": "1.1.2", "hono-openapi": "1.1.2",
"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",
@@ -734,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=="],
@@ -754,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=="],
@@ -1054,11 +1071,11 @@
"@effect/language-service": ["@effect/language-service@0.84.2", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-l04qNxpiA8rY5yXWckRPJ7Mk5MNerXuNymSFf+IdflfI5i8jgL1bpBNLuP6ijg7wgjdHc/KmTnCj2kT0SCntuA=="], "@effect/language-service": ["@effect/language-service@0.84.2", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-l04qNxpiA8rY5yXWckRPJ7Mk5MNerXuNymSFf+IdflfI5i8jgL1bpBNLuP6ijg7wgjdHc/KmTnCj2kT0SCntuA=="],
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-beta.48", "", { "peerDependencies": { "@opentelemetry/api": "^1.9", "@opentelemetry/resources": "^2.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": "^2.0.0", "@opentelemetry/sdk-trace-base": "^2.0.0", "@opentelemetry/sdk-trace-node": "^2.0.0", "@opentelemetry/sdk-trace-web": "^2.0.0", "@opentelemetry/semantic-conventions": "^1.33.0", "effect": "^4.0.0-beta.48" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-vHk/X1vgDrviGcOTHQqzm2D81TtyPE/C7Qdksg5eAdbGpnqL4Dm4lk6PzTReQ0pO1/avIvWqpxy315IURV0Ldw=="], "@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-beta.57", "", { "peerDependencies": { "@opentelemetry/api": "^1.9", "@opentelemetry/resources": "^2.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": "^2.0.0", "@opentelemetry/sdk-trace-base": "^2.0.0", "@opentelemetry/sdk-trace-node": "^2.0.0", "@opentelemetry/sdk-trace-web": "^2.0.0", "@opentelemetry/semantic-conventions": "^1.33.0", "effect": "^4.0.0-beta.57" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-gdjZPEP0QQg4qmI1vd+443kheeQZKytrjJIzCJncy6ZEpyk/SfrqeStLqLXdTRcms3IB0ls0vOV7KNq7YmBRVA=="],
"@effect/platform-node": ["@effect/platform-node@4.0.0-beta.48", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.48", "mime": "^4.1.0", "undici": "^8.0.2" }, "peerDependencies": { "effect": "^4.0.0-beta.48", "ioredis": "^5.7.0" } }, "sha512-8J6H0k9rtbp9O1QvKOyOPRcCTJ8WrR7IzZLJtYFTZ4bXVEEMCTo84h0CRpi7ccpA9t7DLqotip0NeFgiBosNKQ=="], "@effect/platform-node": ["@effect/platform-node@4.0.0-beta.57", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.57", "mime": "^4.1.0", "undici": "^8.0.2" }, "peerDependencies": { "effect": "^4.0.0-beta.57", "ioredis": "^5.7.0" } }, "sha512-la0xxPSAYOsY0d+uVxEBxok3jYB31iPQmIaZZRUj2SNWqcGGHJc6KorKtI8guqSLuv9FGZ255kBWXRbG6hMeeg=="],
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-beta.48", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.20.0" }, "peerDependencies": { "effect": "^4.0.0-beta.48" } }, "sha512-wlhcdDHyacydCgiWdM8JwtQkViQhZsC8uJZ9wMoZXYxlCTvqfdzLeWw4A1UVMoq7sS6/KR1aZVeFkUjrqonncQ=="], "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-beta.57", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.20.0" }, "peerDependencies": { "effect": "^4.0.0-beta.57" } }, "sha512-C976X6f+qHUtLSqcqImuCrjhAHnJV17NC2RvvybsAuDfkyIWU4MyiO2XwgiBeijeNupyr1M/KPKnyjtkNxV9Hw=="],
"@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="], "@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="],
@@ -1462,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=="],
@@ -1542,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"],
@@ -1556,8 +1577,6 @@
"@opencode-ai/sdk": ["@opencode-ai/sdk@workspace:packages/sdk/js"], "@opencode-ai/sdk": ["@opencode-ai/sdk@workspace:packages/sdk/js"],
"@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"],
@@ -1566,7 +1585,7 @@
"@opencode-ai/web": ["@opencode-ai/web@workspace:packages/web"], "@opencode-ai/web": ["@opencode-ai/web@workspace:packages/web"],
"@openrouter/ai-sdk-provider": ["@openrouter/ai-sdk-provider@2.5.1", "", { "peerDependencies": { "ai": "^6.0.0", "zod": "^3.25.0 || ^4.0.0" } }, "sha512-r1fJL1Cb3gQDa2MpWH/sfx1BsEW0uzlRriJM6eihaKqbtKDmZoBisF32VcVaQYassighX7NGCkF68EsrZA43uQ=="], "@openrouter/ai-sdk-provider": ["@openrouter/ai-sdk-provider@2.8.1", "", { "peerDependencies": { "ai": "^6.0.0", "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Y6j3yivgoEUf/kutD/k5GX/mzZfioRFoSx0gbQ+mIOzMaH/vJv1rCkztiuvlLw5xRYQil7oxHUZvmSfXqOx1NQ=="],
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
@@ -1594,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.105", "", { "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.105", "@opentui/core-darwin-x64": "0.1.105", "@opentui/core-linux-arm64": "0.1.105", "@opentui/core-linux-x64": "0.1.105", "@opentui/core-win32-arm64": "0.1.105", "@opentui/core-win32-x64": "0.1.105", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-vllSOOCW6VIThV/96GRLJ1IxIBuR+ci6FDvnPIAG4s7SJ/FW6zAkqDn1xrtBwwk/lM3QWjLqy8BZc+zwWvveJA=="],
"@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.105", "", { "os": "darwin", "cpu": "arm64" }, "sha512-1pIL7aer9amwj8EpYoMNtvavKetIe+nX8uBRmYsMQb+KvJoUAZUqENfRW+qHE5WrsOyxx8/QoyXTHw15GG5iLQ=="],
"@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.105", "", { "os": "darwin", "cpu": "x64" }, "sha512-hLIRSWlK3gY2NRXJGWiTBiMYSmRDjOYFZF6WtUVXhY2SL3sp08dhmr/6dmAVH+3pKCsCipLEsrrcQX6SAihCTA=="],
"@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.105", "", { "os": "linux", "cpu": "arm64" }, "sha512-jlRKfPkozTZEkHEePuCWYcTIUtPm+ieInAwGVqGmjbvqjxdVv1/W/Dt6LEZ/9jpRiOPd+FjXAfLe6wa/XWHr+w=="],
"@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.105", "", { "os": "linux", "cpu": "x64" }, "sha512-kfWS1WMg6qHShmxZX9s1tZc/8JcXw6uyy2UtyTbJdRFExtXGH37oKHi8QK8iPL2ExCx4z7zqVnVJfO3X/Wh7lA=="],
"@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.105", "", { "os": "win32", "cpu": "arm64" }, "sha512-UFx6A8OpBVbGWK6OAw4GqAqKZgIITJfSOd35pG9yDVKQouHN2OGc2HeeXrH2A4h42p40Xl6IfcqqfllkpC13Dg=="],
"@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.105", "", { "os": "win32", "cpu": "x64" }, "sha512-f9FqqUmxehwhF+cgyazm0YT0v0BYTTCPzd6eztqhl74N3x/kC+jOOz2rdJDC/tTBo1JVsF64KupOnhIs6/Cogg=="],
"@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.105", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.105", "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-uxnaMP802sCI487pv/Hk9xdFdIj9mkg3eNliAqbqR0Shmd4phcjKEZvPRpijjmI99j4s9nul71jzF3h1oz31Nw=="],
"@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=="],
@@ -1680,6 +1699,18 @@
"@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-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-android-arm64": ["@oxlint/binding-android-arm64@1.60.0", "", { "os": "android", "cpu": "arm64" }, "sha512-7ANS7PpXCfq84xZQ8E5WPs14gwcuPcl+/8TFNXfpSu0CQBXz3cUo2fDpHT8v8HJN+Ut02eacvMAzTnc9s6X4tw=="],
@@ -2280,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=="],
@@ -2438,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=="],
@@ -2498,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=="],
@@ -2698,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=="],
@@ -3004,11 +3035,11 @@
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
"effect": ["effect@4.0.0-beta.48", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.6.0", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.9", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^13.0.0", "yaml": "^2.8.3" } }, "sha512-MMAM/ZabuNdNmgXiin+BAanQXK7qM8mlt7nfXDoJ/Gn9V8i89JlCq+2N0AiWmqFLXjGLA0u3FjiOjSOYQk5uMw=="], "effect": ["effect@4.0.0-beta.57", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.6.0", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.9", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^13.0.0", "yaml": "^2.8.3" } }, "sha512-rg32VgXnLKaPRs9tbRDaZ5jxmzNY7ojXt85gSHGUTwdlbWH5Ik+OCUY2q14TXliygPGoHwCAvNWS4bQJOqf00g=="],
"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=="],
@@ -3288,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=="],
@@ -3296,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=="],
@@ -4100,6 +4131,8 @@
"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": ["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=="],
@@ -4462,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=="],
@@ -5134,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=="],
@@ -5148,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=="],
@@ -5626,6 +5663,10 @@
"@solidjs/start/vite-plugin-solid": ["vite-plugin-solid@2.11.12", "", { "dependencies": { "@babel/core": "^7.23.3", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^1.8.4", "merge-anything": "^5.1.7", "solid-refresh": "^0.6.3", "vitefu": "^1.0.4" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", "solid-js": "^1.7.2", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-FgjPcx2OwX9h6f28jli7A4bG7PP3te8uyakE5iqsmpq3Jqi1TWLgSroC9N6cMfGRU2zXsl4Q6ISvTr2VL0QHpA=="], "@solidjs/start/vite-plugin-solid": ["vite-plugin-solid@2.11.12", "", { "dependencies": { "@babel/core": "^7.23.3", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^1.8.4", "merge-anything": "^5.1.7", "solid-refresh": "^0.6.3", "vitefu": "^1.0.4" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", "solid-js": "^1.7.2", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-FgjPcx2OwX9h6f28jli7A4bG7PP3te8uyakE5iqsmpq3Jqi1TWLgSroC9N6cMfGRU2zXsl4Q6ISvTr2VL0QHpA=="],
"@standard-community/standard-json/effect": ["effect@4.0.0-beta.48", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.6.0", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.9", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^13.0.0", "yaml": "^2.8.3" } }, "sha512-MMAM/ZabuNdNmgXiin+BAanQXK7qM8mlt7nfXDoJ/Gn9V8i89JlCq+2N0AiWmqFLXjGLA0u3FjiOjSOYQk5uMw=="],
"@standard-community/standard-openapi/effect": ["effect@4.0.0-beta.48", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.6.0", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.9", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^13.0.0", "yaml": "^2.8.3" } }, "sha512-MMAM/ZabuNdNmgXiin+BAanQXK7qM8mlt7nfXDoJ/Gn9V8i89JlCq+2N0AiWmqFLXjGLA0u3FjiOjSOYQk5uMw=="],
"@tailwindcss/oxide/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "@tailwindcss/oxide/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="],
@@ -5664,7 +5705,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=="],
@@ -5674,6 +5715,8 @@
"ai-gateway-provider/@ai-sdk/xai": ["@ai-sdk/xai@3.0.75", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.37", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-V8UKK4fNpI9cnrtsZBvUp9O9J6Y9fTKBRoSLyEaNGPirACewixmLDbXsSgAeownPVWiWpK34bFysd+XouI5Ywg=="], "ai-gateway-provider/@ai-sdk/xai": ["@ai-sdk/xai@3.0.75", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.37", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-V8UKK4fNpI9cnrtsZBvUp9O9J6Y9fTKBRoSLyEaNGPirACewixmLDbXsSgAeownPVWiWpK34bFysd+XouI5Ywg=="],
"ai-gateway-provider/@openrouter/ai-sdk-provider": ["@openrouter/ai-sdk-provider@2.5.1", "", { "peerDependencies": { "ai": "^6.0.0", "zod": "^3.25.0 || ^4.0.0" } }, "sha512-r1fJL1Cb3gQDa2MpWH/sfx1BsEW0uzlRriJM6eihaKqbtKDmZoBisF32VcVaQYassighX7NGCkF68EsrZA43uQ=="],
"ajv-keywords/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], "ajv-keywords/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="],
"ansi-align/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "ansi-align/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
@@ -5882,7 +5925,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=="],
@@ -6542,6 +6585,10 @@
"@solidjs/start/shiki/@shikijs/types": ["@shikijs/types@1.29.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw=="], "@solidjs/start/shiki/@shikijs/types": ["@shikijs/types@1.29.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw=="],
"@standard-community/standard-json/effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"@standard-community/standard-openapi/effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
"@vitest/expect/@vitest/utils/@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="], "@vitest/expect/@vitest/utils/@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="],
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": {
+3 -3
View File
@@ -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") {
@@ -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`)
+24 -1
View File
@@ -115,6 +115,27 @@ const zenLiteCouponFirstMonth100 = new stripe.Coupon("ZenLiteCouponFirstMonth100
appliesToProducts: [zenLiteProduct.id], appliesToProducts: [zenLiteProduct.id],
duration: "once", duration: "once",
}) })
const zenLiteCouponThreeMonths100 = new stripe.Coupon("ZenLiteCoupon3Months100", {
name: "3 months 100% off",
percentOff: 100,
appliesToProducts: [zenLiteProduct.id],
duration: "repeating",
durationInMonths: 3,
})
const zenLiteCouponSixMonths100 = new stripe.Coupon("ZenLiteCoupon6Months100", {
name: "6 months 100% off",
percentOff: 100,
appliesToProducts: [zenLiteProduct.id],
duration: "repeating",
durationInMonths: 6,
})
const zenLiteCouponTwelveMonths100 = new stripe.Coupon("ZenLiteCoupon12Months100", {
name: "12 months 100% off",
percentOff: 100,
appliesToProducts: [zenLiteProduct.id],
duration: "repeating",
durationInMonths: 12,
})
const zenLitePrice = new stripe.Price("ZenLitePrice", { const zenLitePrice = new stripe.Price("ZenLitePrice", {
product: zenLiteProduct.id, product: zenLiteProduct.id,
currency: "usd", currency: "usd",
@@ -131,6 +152,9 @@ const ZEN_LITE_PRICE = new sst.Linkable("ZEN_LITE_PRICE", {
priceInr: 92900, priceInr: 92900,
firstMonth50Coupon: zenLiteCouponFirstMonth50.id, firstMonth50Coupon: zenLiteCouponFirstMonth50.id,
firstMonth100Coupon: zenLiteCouponFirstMonth100.id, firstMonth100Coupon: zenLiteCouponFirstMonth100.id,
threeMonths100Coupon: zenLiteCouponThreeMonths100.id,
sixMonths100Coupon: zenLiteCouponSixMonths100.id,
twelveMonths100Coupon: zenLiteCouponTwelveMonths100.id,
}, },
}) })
@@ -236,7 +260,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,
+4 -4
View File
@@ -1,8 +1,8 @@
{ {
"nodeModules": { "nodeModules": {
"x86_64-linux": "sha256-VIgTxIjmZ4Bfwwdj/YFmRJdBpPHYhJSY31kh06EXX+0=", "x86_64-linux": "sha256-h2T/LnUnISZZDn9ZQkZ/A59P+6+QdfOlrgl4RXK/vgM=",
"aarch64-linux": "sha256-9118AS1ED0nrliURgZYBRuF/18RqXpUouhYJRlZ6jeA=", "aarch64-linux": "sha256-+DRohG1ZEB/2LtZU90GWoqJkeyu/sW8A8oKT3f/TtQ0=",
"aarch64-darwin": "sha256-ppo3MfSIGKQHJCdYEZiLFRc61PtcJ9J0kAXH1pNIonA=", "aarch64-darwin": "sha256-k4nsk/WduuxY8HgjRuqzGT9EjEo7V/2mAzBTYee0fZ0=",
"x86_64-darwin": "sha256-m+CZSOglBCTfNzbdBX6hXdDqqOzHNMzAddVp6BZVDtU=" "x86_64-darwin": "sha256-3dSvfN2+5lXwOx57x8NSIWbEZ1fp6+1T6bJpAuUNPyk="
} }
} }
+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 running on rosetta2
++ lib.optional stdenvNoCC.hostPlatform.isDarwin sysctl
)
} }
''
+ ''
runHook postInstall runHook postInstall
''; '';
+12 -7
View File
@@ -4,10 +4,10 @@
"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",
@@ -27,13 +27,15 @@
"packages/slack" "packages/slack"
], ],
"catalog": { "catalog": {
"@effect/opentelemetry": "4.0.0-beta.48", "@effect/opentelemetry": "4.0.0-beta.57",
"@effect/platform-node": "4.0.0-beta.48", "@effect/platform-node": "4.0.0-beta.57",
"@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.105",
"@opentui/solid": "0.1.105",
"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",
@@ -44,14 +46,15 @@
"@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",
"dompurify": "3.3.1", "dompurify": "3.3.1",
"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.57",
"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",
@@ -87,6 +90,7 @@
"glob": "13.0.5", "glob": "13.0.5",
"husky": "9.1.7", "husky": "9.1.7",
"oxlint": "1.60.0", "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",
@@ -124,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.28",
"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",
+27 -10
View File
@@ -82,7 +82,15 @@ declare global {
} }
function QueryProvider(props: ParentProps) { function QueryProvider(props: ParentProps) {
const client = new QueryClient() const client = new QueryClient({
defaultOptions: {
queries: {
refetchOnReconnect: false,
refetchOnMount: false,
refetchOnWindowFocus: false,
},
},
})
return <QueryClientProvider client={client}>{props.children}</QueryClientProvider> return <QueryClientProvider client={client}>{props.children}</QueryClientProvider>
} }
@@ -121,10 +129,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 +149,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>
@@ -184,32 +190,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>
) )
} }
@@ -284,6 +299,7 @@ export function AppInterface(props: {
> >
<ConnectionGate disableHealthCheck={props.disableHealthCheck}> <ConnectionGate disableHealthCheck={props.disableHealthCheck}>
<ServerKey> <ServerKey>
<QueryProvider>
<GlobalSDKProvider> <GlobalSDKProvider>
<GlobalSyncProvider> <GlobalSyncProvider>
<Dynamic <Dynamic
@@ -298,6 +314,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)
@@ -1,13 +1,12 @@
import { useMutation } from "@tanstack/solid-query" import { useMutation, useQueryClient } from "@tanstack/solid-query"
import { Component, createEffect, createMemo, on, Show } from "solid-js" import { Component, createMemo, Show } from "solid-js"
import { createStore } from "solid-js/store"
import { useSync } from "@/context/sync" import { useSync } from "@/context/sync"
import { useSDK } from "@/context/sdk" import { useSDK } from "@/context/sdk"
import { Dialog } from "@opencode-ai/ui/dialog" import { Dialog } from "@opencode-ai/ui/dialog"
import { List } from "@opencode-ai/ui/list" import { List } from "@opencode-ai/ui/list"
import { Switch } from "@opencode-ai/ui/switch" import { Switch } from "@opencode-ai/ui/switch"
import { showToast } from "@opencode-ai/ui/toast"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
import { loadMcpQuery } from "@/context/global-sync"
const statusLabels = { const statusLabels = {
connected: "mcp.status.connected", connected: "mcp.status.connected",
@@ -20,48 +19,7 @@ export const DialogSelectMcp: Component = () => {
const sync = useSync() const sync = useSync()
const sdk = useSDK() const sdk = useSDK()
const language = useLanguage() const language = useLanguage()
const [state, setState] = createStore({ const queryClient = useQueryClient()
done: false,
loading: false,
})
createEffect(
on(
() => sync.data.mcp_ready,
(ready, prev) => {
if (!ready && prev) setState("done", false)
},
{ defer: true },
),
)
createEffect(() => {
if (state.done || state.loading) return
if (sync.data.mcp_ready) {
setState("done", true)
return
}
setState("loading", true)
void sdk.client.mcp
.status()
.then((result) => {
sync.set("mcp", result.data ?? {})
sync.set("mcp_ready", true)
setState("done", true)
})
.catch((err) => {
setState("done", true)
showToast({
variant: "error",
title: language.t("common.requestFailed"),
description: err instanceof Error ? err.message : String(err),
})
})
.finally(() => {
setState("loading", false)
})
})
const items = createMemo(() => const items = createMemo(() =>
Object.entries(sync.data.mcp ?? {}) Object.entries(sync.data.mcp ?? {})
@@ -71,16 +29,10 @@ export const DialogSelectMcp: Component = () => {
const toggle = useMutation(() => ({ const toggle = useMutation(() => ({
mutationFn: async (name: string) => { mutationFn: async (name: string) => {
const status = sync.data.mcp[name] if (sync.data.mcp[name]?.status === "connected") await sdk.client.mcp.disconnect({ name })
if (status?.status === "connected") { else await sdk.client.mcp.connect({ name })
await sdk.client.mcp.disconnect({ name })
} else {
await sdk.client.mcp.connect({ name })
}
const result = await sdk.client.mcp.status()
if (result.data) sync.set("mcp", result.data)
}, },
onSuccess: () => queryClient.refetchQueries({ queryKey: loadMcpQuery(sync.directory).queryKey }),
})) }))
const enabledCount = createMemo(() => items().filter((i) => i.status === "connected").length) const enabledCount = createMemo(() => items().filter((i) => i.status === "connected").length)
@@ -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={
+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, 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?.()
} }
+216 -48
View File
@@ -11,7 +11,9 @@ import { showToast } from "@opencode-ai/ui/toast"
import { useParams } from "@solidjs/router" import { useParams } from "@solidjs/router"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
import { usePermission } from "@/context/permission" import { usePermission } from "@/context/permission"
import { usePlatform } from "@/context/platform" import { usePlatform, type DisplayBackend } from "@/context/platform"
import { useGlobalSync } from "@/context/global-sync"
import { useGlobalSDK } from "@/context/global-sdk"
import { import {
monoDefault, monoDefault,
monoFontFamily, monoFontFamily,
@@ -19,6 +21,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"
@@ -37,6 +42,18 @@ type ThemeOption = {
name: string name: string
} }
type ShellOption = {
path: string
name: string
acceptable: boolean
}
type ShellSelectOption = {
id: string
value: string
label: string
}
// To prevent audio from overlapping/playing very quickly when navigating the settings menus, // To prevent audio from overlapping/playing very quickly when navigating the settings menus,
// delay the playback by 100ms during quick selection changes and pause existing sounds. // delay the playback by 100ms during quick selection changes and pause existing sounds.
const stopDemoSound = () => { const stopDemoSound = () => {
@@ -72,10 +89,6 @@ export const SettingsGeneral: Component = () => {
const params = useParams() const params = useParams()
const settings = useSettings() const settings = useSettings()
onMount(() => {
void theme.loadThemes()
})
const [store, setStore] = createStore({ const [store, setStore] = createStore({
checking: false, checking: false,
}) })
@@ -106,6 +119,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 +138,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!()
}, },
}, },
{ {
@@ -163,6 +175,70 @@ export const SettingsGeneral: Component = () => {
const themeOptions = createMemo<ThemeOption[]>(() => theme.ids().map((id) => ({ id, name: theme.name(id) }))) const themeOptions = createMemo<ThemeOption[]>(() => theme.ids().map((id) => ({ id, name: theme.name(id) })))
const globalSync = useGlobalSync()
const globalSdk = useGlobalSDK()
const [shells] = createResource(
() =>
globalSdk.client.pty
.shells()
.then((res) => res.data ?? [])
.catch(() => [] as ShellOption[]),
{ initialValue: [] as ShellOption[] },
)
const [displayBackend, { refetch: refetchDisplayBackend }] = createResource(
() => (linux() && platform.getDisplayBackend ? true : false),
() => Promise.resolve(platform.getDisplayBackend?.() ?? null).catch(() => null as DisplayBackend | null),
{ initialValue: null as DisplayBackend | null },
)
onMount(() => {
void theme.loadThemes()
})
const autoOption = { id: "auto", value: "", label: language.t("settings.general.row.shell.autoDefault") }
const currentShell = createMemo(() => globalSync.data.config.shell ?? "")
const shellOptions = createMemo<ShellSelectOption[]>(() => {
const list = shells.latest
const current = globalSync.data.config.shell
const nameCounts = new Map<string, number>()
for (const s of list) {
nameCounts.set(s.name, (nameCounts.get(s.name) || 0) + 1)
}
const options = [
autoOption,
...list.map((s) => {
const ambiguousName = (nameCounts.get(s.name) || 0) > 1
const text = ambiguousName ? s.path : s.name
const label = s.acceptable ? text : `${text} (${language.t("settings.general.row.shell.terminalOnly")})`
return {
id: s.path,
// Prefer name over path - "bash" is much cleaner than the explicit full route even when it may change due to PATH.
value: ambiguousName ? s.path : s.name,
label,
}
}),
]
if (current && !options.some((o) => o.value === current)) {
options.push({ id: current, value: current, label: current })
}
return options
})
const onDisplayBackendChange = (checked: boolean) => {
const update = platform.setDisplayBackend?.(checked ? "wayland" : "auto")
if (!update) return
void update.finally(() => {
void refetchDisplayBackend()
})
}
const colorSchemeOptions = createMemo((): { value: ColorScheme; label: string }[] => [ const colorSchemeOptions = createMemo((): { value: ColorScheme; label: string }[] => [
{ value: "system", label: language.t("theme.scheme.system") }, { value: "system", label: language.t("theme.scheme.system") },
{ value: "light", label: language.t("theme.scheme.light") }, { value: "light", label: language.t("theme.scheme.light") },
@@ -180,6 +256,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,
@@ -240,6 +317,27 @@ export const SettingsGeneral: Component = () => {
</div> </div>
</SettingsRow> </SettingsRow>
<SettingsRow
title={language.t("settings.general.row.shell.title")}
description={language.t("settings.general.row.shell.description")}
>
<Select
data-action="settings-shell"
options={shellOptions()}
current={shellOptions().find((o) => o.value === currentShell()) ?? autoOption}
value={(o) => o.id}
label={(o) => o.label}
onSelect={(option) => {
if (!option) return
globalSync.updateConfig({ shell: option.value })
}}
variant="secondary"
size="small"
triggerVariant="settings"
triggerStyle={{ "min-width": "180px" }}
/>
</SettingsRow>
<SettingsRow <SettingsRow
title={language.t("settings.general.row.reasoningSummaries.title")} title={language.t("settings.general.row.reasoningSummaries.title")}
description={language.t("settings.general.row.reasoningSummaries.description")} description={language.t("settings.general.row.reasoningSummaries.description")}
@@ -275,6 +373,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 +560,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 +728,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)]">
@@ -544,45 +746,9 @@ export const SettingsGeneral: Component = () => {
<SoundsSection /> <SoundsSection />
{/*<Show when={platform.platform === "desktop" && platform.os === "windows" && platform.getWslEnabled}>
{(_) => {
const [enabledResource, actions] = createResource(() => platform.getWslEnabled?.())
const enabled = () => (enabledResource.state === "pending" ? undefined : enabledResource.latest)
return (
<div class="flex flex-col gap-1">
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.desktop.section.wsl")}</h3>
<SettingsList>
<SettingsRow
title={language.t("settings.desktop.wsl.title")}
description={language.t("settings.desktop.wsl.description")}
>
<div data-action="settings-wsl">
<Switch
checked={enabled() ?? false}
disabled={enabledResource.state === "pending"}
onChange={(checked) => platform.setWslEnabled?.(checked)?.finally(() => actions.refetch())}
/>
</div>
</SettingsRow>
</SettingsList>
</div>
)
}}
</Show>*/}
<UpdatesSection /> <UpdatesSection />
<Show when={linux()}> <Show when={linux()}>
{(_) => {
const [valueResource, actions] = createResource(() => platform.getDisplayBackend?.())
const value = () => (valueResource.state === "pending" ? undefined : valueResource.latest)
const onChange = (checked: boolean) =>
platform.setDisplayBackend?.(checked ? "wayland" : "auto").finally(() => actions.refetch())
return (
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.display")}</h3> <h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.display")}</h3>
@@ -601,13 +767,15 @@ export const SettingsGeneral: Component = () => {
description={language.t("settings.general.row.wayland.description")} description={language.t("settings.general.row.wayland.description")}
> >
<div data-action="settings-wayland"> <div data-action="settings-wayland">
<Switch checked={value() === "wayland"} onChange={onChange} /> <Switch checked={displayBackend.latest === "wayland"} onChange={onDisplayBackendChange} />
</div> </div>
</SettingsRow> </SettingsRow>
</SettingsList> </SettingsList>
</div> </div>
) </Show>
}}
<Show when={desktop() && import.meta.env.VITE_OPENCODE_CHANNEL === "beta"}>
<AdvancedSection />
</Show> </Show>
</div> </div>
</div> </div>
@@ -3,7 +3,7 @@ import { useDialog } from "@opencode-ai/ui/context/dialog"
import { Icon } from "@opencode-ai/ui/icon" import { Icon } from "@opencode-ai/ui/icon"
import { Switch } from "@opencode-ai/ui/switch" import { Switch } from "@opencode-ai/ui/switch"
import { Tabs } from "@opencode-ai/ui/tabs" import { Tabs } from "@opencode-ai/ui/tabs"
import { useMutation } from "@tanstack/solid-query" import { useMutation, useQueryClient } from "@tanstack/solid-query"
import { showToast } from "@opencode-ai/ui/toast" import { showToast } from "@opencode-ai/ui/toast"
import { useNavigate } from "@solidjs/router" import { useNavigate } from "@solidjs/router"
import { type Accessor, createEffect, createMemo, For, type JSXElement, onCleanup, Show } from "solid-js" import { type Accessor, createEffect, createMemo, For, type JSXElement, onCleanup, Show } from "solid-js"
@@ -15,6 +15,7 @@ import { useSDK } from "@/context/sdk"
import { normalizeServerUrl, ServerConnection, useServer } from "@/context/server" import { normalizeServerUrl, ServerConnection, useServer } from "@/context/server"
import { useSync } from "@/context/sync" import { useSync } from "@/context/sync"
import { useCheckServerHealth, type ServerHealth } from "@/utils/server-health" import { useCheckServerHealth, type ServerHealth } from "@/utils/server-health"
import { loadMcpQuery } from "@/context/global-sync"
const pollMs = 10_000 const pollMs = 10_000
@@ -137,14 +138,14 @@ const useMcpToggleMutation = () => {
const sync = useSync() const sync = useSync()
const sdk = useSDK() const sdk = useSDK()
const language = useLanguage() const language = useLanguage()
const queryClient = useQueryClient()
return useMutation(() => ({ return useMutation(() => ({
mutationFn: async (name: string) => { mutationFn: async (name: string) => {
const status = sync.data.mcp[name] const status = sync.data.mcp[name]
await (status?.status === "connected" ? sdk.client.mcp.disconnect({ name }) : sdk.client.mcp.connect({ name })) await (status?.status === "connected" ? sdk.client.mcp.disconnect({ name }) : sdk.client.mcp.connect({ name }))
const result = await sdk.client.mcp.status()
if (result.data) sync.set("mcp", result.data)
}, },
onSuccess: () => queryClient.refetchQueries({ queryKey: loadMcpQuery(sync.directory).queryKey }),
onError: (err) => { onError: (err) => {
showToast({ showToast({
variant: "error", variant: "error",
@@ -162,14 +163,6 @@ export function StatusPopoverBody(props: { shown: Accessor<boolean> }) {
const dialog = useDialog() const dialog = useDialog()
const language = useLanguage() const language = useLanguage()
const navigate = useNavigate() const navigate = useNavigate()
const sdk = useSDK()
const [load, setLoad] = createStore({
lspDone: false,
lspLoading: false,
mcpDone: false,
mcpLoading: false,
})
const fail = (err: unknown) => { const fail = (err: unknown) => {
showToast({ showToast({
@@ -181,40 +174,6 @@ export function StatusPopoverBody(props: { shown: Accessor<boolean> }) {
createEffect(() => { createEffect(() => {
if (!props.shown()) return if (!props.shown()) return
if (!sync.data.mcp_ready && !load.mcpDone && !load.mcpLoading) {
setLoad("mcpLoading", true)
void sdk.client.mcp
.status()
.then((result) => {
sync.set("mcp", result.data ?? {})
sync.set("mcp_ready", true)
})
.catch((err) => {
setLoad("mcpDone", true)
fail(err)
})
.finally(() => {
setLoad("mcpLoading", false)
})
}
if (!sync.data.lsp_ready && !load.lspDone && !load.lspLoading) {
setLoad("lspLoading", true)
void sdk.client.lsp
.status()
.then((result) => {
sync.set("lsp", result.data ?? [])
sync.set("lsp_ready", true)
})
.catch((err) => {
setLoad("lspDone", true)
fail(err)
})
.finally(() => {
setLoad("lspLoading", false)
})
}
}) })
let dialogRun = 0 let dialogRun = 0
+6 -6
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) => {
+15 -6
View File
@@ -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()
+109 -107
View File
@@ -8,24 +8,31 @@ 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,
loadGlobalConfigQuery,
loadPathQuery,
loadProjectsQuery,
loadProvidersQuery,
} from "./global-sync/bootstrap"
import { createChildStoreManager } from "./global-sync/child-store" import { createChildStoreManager } from "./global-sync/child-store"
import { applyDirectoryEvent, applyGlobalEvent, cleanupDroppedSessionCaches } from "./global-sync/event-reducer" import { applyDirectoryEvent, applyGlobalEvent, cleanupDroppedSessionCaches } from "./global-sync/event-reducer"
import { createRefreshQueue } from "./global-sync/queue"
import { clearSessionPrefetchDirectory } from "./global-sync/session-prefetch" import { clearSessionPrefetchDirectory } from "./global-sync/session-prefetch"
import { estimateRootSessionTotal, loadRootSessionsWithFallback } from "./global-sync/session-load" import { estimateRootSessionTotal, loadRootSessionsWithFallback } from "./global-sync/session-load"
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, useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/solid-query"
import { createRefreshQueue } from "./global-sync/queue"
type GlobalStore = { type GlobalStore = {
ready: boolean ready: boolean
@@ -41,6 +48,21 @@ type GlobalStore = {
reload: undefined | "pending" | "complete" reload: undefined | "pending" | "complete"
} }
export const loadSessionsQuery = (directory: string) =>
queryOptions<null>({ queryKey: [directory, "loadSessions"], queryFn: skipToken })
export const loadMcpQuery = (directory: string, sdk?: OpencodeClient) =>
queryOptions({
queryKey: [directory, "mcp"],
queryFn: sdk ? () => sdk.mcp.status().then((r) => r.data ?? {}) : skipToken,
})
export const loadLspQuery = (directory: string, sdk?: OpencodeClient) =>
queryOptions({
queryKey: [directory, "lsp"],
queryFn: sdk ? () => sdk.lsp.status().then((r) => r.data ?? []) : skipToken,
})
function createGlobalSync() { function createGlobalSync() {
const globalSDK = useGlobalSDK() const globalSDK = useGlobalSDK()
const language = useLanguage() const language = useLanguage()
@@ -52,53 +74,49 @@ 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( const [configQuery, providerQuery, pathQuery] = useQueries(() => ({
Persist.global("globalSync.project", ["globalSync.project.v1"]), queries: [loadGlobalConfigQuery(), loadProvidersQuery(null), loadPathQuery(null), loadProjectsQuery()],
createStore({ value: [] as Project[] }), }))
)
const [globalStore, setGlobalStore] = createStore<GlobalStore>({ const [globalStore, setGlobalStore] = createStore<GlobalStore>({
ready: false, get ready() {
path: { state: "", config: "", worktree: "", directory: "", home: "" }, return bootstrap.isPending
project: projectCache.value, },
project: [],
session_todo: {}, session_todo: {},
provider: { all: [], connected: [], default: {} },
provider_auth: {}, provider_auth: {},
config: {}, get path() {
reload: undefined, const EMPTY = { state: "", config: "", worktree: "", directory: "", home: "" }
if (pathQuery.isLoading) return EMPTY
return pathQuery.data ?? EMPTY
},
get provider() {
const EMPTY = { all: [], connected: [], default: {} }
if (providerQuery.isLoading) return EMPTY
return providerQuery.data ?? EMPTY
},
get config() {
if (configQuery.isLoading) return {}
return configQuery.data ?? {}
},
get reload() {
return updateConfigMutation.isPending ? "pending" : 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[]) => {
@@ -109,24 +127,30 @@ function createGlobalSync() {
return (setGlobalStore as (...args: unknown[]) => unknown)(...input) return (setGlobalStore as (...args: unknown[]) => unknown)(...input)
}) as typeof setGlobalStore }) as typeof setGlobalStore
const bootstrap = useQuery(() => ({
queryKey: ["bootstrap"],
queryFn: async () => {
await bootstrapGlobal({
globalSDK: globalSDK.client,
requestFailedTitle: language.t("common.requestFailed"),
translate: language.t,
formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }),
setGlobalStore: setBootStore,
queryClient,
})
bootedAt = Date.now()
return bootedAt
},
}))
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) {
@@ -145,10 +169,21 @@ function createGlobalSync() {
const queue = createRefreshQueue({ const queue = createRefreshQueue({
paused, paused,
bootstrap, bootstrap: () => queryClient.fetchQuery({ queryKey: ["bootstrap"] }),
bootstrapInstance, bootstrapInstance,
}) })
const sdkFor = (directory: string) => {
const cached = sdkCache.get(directory)
if (cached) return cached
const sdk = globalSDK.createClient({
directory,
throwOnError: true,
})
sdkCache.set(directory, sdk)
return sdk
}
const children = createChildStoreManager({ const children = createChildStoreManager({
owner, owner,
isBooting: (directory) => booting.has(directory), isBooting: (directory) => booting.has(directory),
@@ -164,19 +199,9 @@ function createGlobalSync() {
clearSessionPrefetchDirectory(directory) clearSessionPrefetchDirectory(directory)
}, },
translate: language.t, translate: language.t,
getSdk: sdkFor,
}) })
const sdkFor = (directory: string) => {
const cached = sdkCache.get(directory)
if (cached) return cached
const sdk = globalSDK.createClient({
directory,
throwOnError: true,
})
sdkCache.set(directory, sdk)
return sdk
}
async function loadSessions(directory: string) { async function loadSessions(directory: string) {
const pending = sessionLoads.get(directory) const pending = sessionLoads.get(directory)
if (pending) return pending if (pending) return pending
@@ -198,7 +223,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 +243,7 @@ function createGlobalSync() {
limit, limit,
permission: store.permission, permission: store.permission,
}) })
batch(() => {
setStore( setStore(
"sessionTotal", "sessionTotal",
estimateRootSessionTotal({ estimateRootSessionTotal({
@@ -224,6 +254,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 +266,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 +284,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 +303,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)
}) })
@@ -291,7 +326,7 @@ function createGlobalSync() {
project: globalStore.project, project: globalStore.project,
refresh: () => { refresh: () => {
if (recent) return if (recent) return
queue.refresh() bootstrap.refetch()
}, },
setGlobalProject: setProjects, setGlobalProject: setProjects,
}) })
@@ -317,12 +352,7 @@ function createGlobalSync() {
setSessionTodo, setSessionTodo,
vcsCache: children.vcsCache.get(directory), vcsCache: children.vcsCache.get(directory),
loadLsp: () => { loadLsp: () => {
sdkFor(directory) void queryClient.fetchQuery(loadLspQuery(directory, sdkFor(directory)))
.lsp.status()
.then((x) => {
setStore("lsp", x.data ?? [])
setStore("lsp_ready", true)
})
}, },
}) })
}) })
@@ -337,38 +367,21 @@ function createGlobalSync() {
} }
}) })
async function bootstrap() {
bootingRoot = true
try {
await bootstrapGlobal({
globalSDK: globalSDK.client,
requestFailedTitle: language.t("common.requestFailed"),
translate: language.t,
formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }),
setGlobalStore: setBootStore,
})
bootedAt = Date.now()
} finally {
bootingRoot = false
}
}
onMount(() => { onMount(() => {
if (typeof requestAnimationFrame === "function") { if (typeof requestAnimationFrame === "function") {
eventFrame = requestAnimationFrame(() => { eventFrame = requestAnimationFrame(() => {
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()
}) })
const projectApi = { const projectApi = {
@@ -381,21 +394,10 @@ function createGlobalSync() {
}, },
} }
const updateConfig = async (config: Config) => { const updateConfigMutation = useMutation(() => ({
setGlobalStore("reload", "pending") mutationFn: (config: Config) => globalSDK.client.global.config.update({ config }),
return globalSDK.client.global.config onSuccess: () => bootstrap.refetch(),
.update({ config }) }))
.then(bootstrap)
.then(() => {
queue.refresh()
setGlobalStore("reload", undefined)
queue.refresh()
})
.catch((error) => {
setGlobalStore("reload", undefined)
throw error
})
}
return { return {
data: globalStore, data: globalStore,
@@ -408,8 +410,8 @@ function createGlobalSync() {
}, },
child: children.child, child: children.child,
peek: children.peek, peek: children.peek,
bootstrap, // bootstrap,
updateConfig, updateConfig: updateConfigMutation.mutateAsync,
project: projectApi, project: projectApi,
todo: { todo: {
set: setSessionTodo, set: setSessionTodo,
+133 -97
View File
@@ -11,13 +11,15 @@ 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"
import { loadMcpQuery } from "../global-sync"
type GlobalStore = { type GlobalStore = {
ready: boolean ready: boolean
@@ -65,55 +67,79 @@ 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 const loadGlobalConfigQuery = (
sdk?: OpencodeClient,
transform?: (x: Awaited<ReturnType<OpencodeClient["global"]["config"]["get"]>>) => void,
) =>
queryOptions({
queryKey: ["config"],
queryFn: sdk
? () =>
retry(() =>
sdk.global.config.get().then((x) => {
transform?.(x)
return x.data!
}),
)
: skipToken,
})
export const loadProjectsQuery = (
sdk?: OpencodeClient,
transform?: (x: Awaited<ReturnType<OpencodeClient["project"]["list"]>>["data"]) => void,
) =>
queryOptions({
queryKey: ["project"],
queryFn: sdk
? () =>
retry(() =>
sdk.project
.list()
.then((x) => {
return (x.data ?? [])
.filter((p) => !!p?.id)
.filter((p) => !!p.worktree && !p.worktree.includes("opencode-test"))
.slice()
.sort((a, b) => cmp(a.id, b.id))
})
.then(transform),
)
: skipToken,
})
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 = [
() =>
retry(() =>
input.globalSDK.global.config.get().then((x) => {
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(loadGlobalConfigQuery(input.globalSDK)),
() => input.queryClient.fetchQuery(loadProvidersQuery(null, input.globalSDK)),
() => input.queryClient.fetchQuery(loadPathQuery(null, input.globalSDK)),
() => () =>
retry(() => input.queryClient.fetchQuery(
input.globalSDK.path.get().then((x) => { loadProjectsQuery(input.globalSDK, (data) => input.setGlobalStore("project", data ?? [])),
input.setGlobalStore("path", x.data!)
}),
),
() =>
retry(() =>
input.globalSDK.project.list().then((x) => {
const projects = (x.data ?? [])
.filter((p) => !!p?.id)
.filter((p) => !!p.worktree && !p.worktree.includes("opencode-test"))
.slice()
.sort((a, b) => cmp(a.id, b.id))
input.setGlobalStore("project", projects)
}),
), ),
] ]
await runAll(fast)
// showErrors({
// errors: errors(await runAll(fast)),
// title: input.requestFailedTitle,
// translate: input.translate,
// formatMoreCount: input.formatMoreCount,
// })
await waitForPaint()
await runAll(slow) await runAll(slow)
// showErrors({ // showErrors({
// errors: errors(), // errors: errors(),
@@ -121,7 +147,6 @@ export async function bootstrapGlobal(input: {
// translate: input.translate, // translate: input.translate,
// formatMoreCount: input.formatMoreCount, // formatMoreCount: input.formatMoreCount,
// }) // })
input.setGlobalStore("ready", true)
} }
function groupBySession<T extends { id: string; sessionID: string }>(input: T[]) { function groupBySession<T extends { id: string; sessionID: string }>(input: T[]) {
@@ -172,6 +197,48 @@ function warmSessions(input: {
).then(() => undefined) ).then(() => undefined)
} }
export const loadProvidersQuery = (directory: string | null, sdk?: OpencodeClient) =>
queryOptions({
queryKey: [directory, "providers"],
queryFn: sdk ? () => retry(() => sdk.provider.list().then((x) => normalizeProviderList(x.data!))) : skipToken,
})
export const loadAgentsQuery = (
directory: string | null,
sdk?: OpencodeClient,
transform?: (x: Awaited<ReturnType<OpencodeClient["app"]["agents"]>>) => void,
) =>
queryOptions({
queryKey: [directory, "agents"],
queryFn: sdk
? () =>
retry(() =>
sdk.app.agents().then((x) => {
transform?.(x)
return x.data!
}),
)
: skipToken,
})
export const loadPathQuery = (
directory: string | null,
sdk?: OpencodeClient,
transform?: (x: Awaited<ReturnType<OpencodeClient["path"]["get"]>>) => void,
) =>
queryOptions<Path>({
queryKey: [directory, "path"],
queryFn: sdk
? () =>
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
@@ -186,6 +253,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)
@@ -196,38 +264,32 @@ export async function bootstrapDirectory(input: {
input.setStore("provider", input.global.provider) input.setStore("provider", input.global.provider)
} }
if (Object.keys(input.store.config).length === 0 && Object.keys(input.global.config).length > 0) { if (Object.keys(input.store.config).length === 0 && Object.keys(input.global.config).length > 0) {
input.setStore("config", input.global.config) input.setStore("config", reconcile(input.global.config, { merge: false }))
} }
if (loading || input.store.provider.all.length === 0) {
input.setStore("provider_ready", false)
}
input.setStore("mcp_ready", false)
input.setStore("mcp", {})
input.setStore("lsp_ready", false)
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)
() => retry(() => input.sdk.config.get().then((x) => input.setStore("config", x.data!))), ;(async () => {
() => retry(() => input.sdk.session.status().then((x) => input.setStore("session_status", x.data!))),
]
const slow = [ const slow = [
() => Promise.resolve(input.loadSessions(input.directory)),
() => () =>
seededProject input.queryClient.ensureQueryData(
? Promise.resolve() loadAgentsQuery(input.directory, input.sdk, (x) => input.setStore("agent", normalizeAgentList(x.data))),
: retry(() => input.sdk.project.current()).then((x) => input.setStore("project", x.data!.id)), ),
() => () =>
seededPath retry(() => input.sdk.config.get().then((x) => input.setStore("config", reconcile(x.data!, { merge: false })))),
? Promise.resolve() () => retry(() => input.sdk.session.status().then((x) => input.setStore("session_status", x.data!))),
: retry(() => !seededProject &&
input.sdk.path.get().then((x) => { (() => retry(() => input.sdk.project.current()).then((x) => input.setStore("project", x.data!.id))),
input.setStore("path", x.data!) !seededPath &&
(() =>
input.queryClient.ensureQueryData(
loadPathQuery(input.directory, input.sdk, (x) => {
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) => {
@@ -290,25 +352,17 @@ export async function bootstrapDirectory(input: {
}), }),
), ),
() => Promise.resolve(input.loadSessions(input.directory)), () => Promise.resolve(input.loadSessions(input.directory)),
() => input.queryClient.fetchQuery(loadMcpQuery(input.directory, input.sdk)),
() => () =>
retry(() => input.queryClient.fetchQuery(loadProvidersQuery(input.directory, input.sdk)).catch((err) => {
input.sdk.mcp.status().then((x) => {
input.setStore("mcp", x.data!)
input.setStore("mcp_ready", true)
}),
),
]
const errs = errors(await runAll(fast))
if (errs.length > 0) {
console.error("Failed to bootstrap instance", errs[0])
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),
}) })
} }),
].filter(Boolean) as (() => Promise<any>)[]
await waitForPaint() await waitForPaint()
const slowErrs = errors(await runAll(slow)) const slowErrs = errors(await runAll(slow))
@@ -322,24 +376,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),
})
})
} }
@@ -22,6 +22,7 @@ describe("createChildStoreManager", () => {
onBootstrap() {}, onBootstrap() {},
onDispose() {}, onDispose() {},
translate: (key) => key, translate: (key) => key,
getSdk: () => null!,
}) })
Array.from({ length: 30 }, (_, index) => `/pinned-${index}`).forEach((directory) => { Array.from({ length: 30 }, (_, index) => `/pinned-${index}`).forEach((directory) => {
@@ -1,7 +1,7 @@
import { createRoot, getOwner, onCleanup, runWithOwner, type Owner } from "solid-js" import { createRoot, getOwner, onCleanup, runWithOwner, type Owner } from "solid-js"
import { createStore, type SetStoreFunction, type Store } from "solid-js/store" import { createStore, type SetStoreFunction, type Store } from "solid-js/store"
import { Persist, persisted } from "@/utils/persist" import { Persist, persisted } from "@/utils/persist"
import type { VcsInfo } from "@opencode-ai/sdk/v2/client" import type { OpencodeClient, VcsInfo } from "@opencode-ai/sdk/v2/client"
import { import {
DIR_IDLE_TTL_MS, DIR_IDLE_TTL_MS,
MAX_DIR_STORES, MAX_DIR_STORES,
@@ -14,6 +14,9 @@ import {
type VcsCache, type VcsCache,
} from "./types" } from "./types"
import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction" import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction"
import { useQueries } from "@tanstack/solid-query"
import { loadPathQuery, loadProvidersQuery } from "./bootstrap"
import { loadLspQuery, loadMcpQuery } from "../global-sync"
export function createChildStoreManager(input: { export function createChildStoreManager(input: {
owner: Owner owner: Owner
@@ -22,6 +25,7 @@ export function createChildStoreManager(input: {
onBootstrap: (directory: string) => void onBootstrap: (directory: string) => void
onDispose: (directory: string) => void onDispose: (directory: string) => void
translate: (key: string, vars?: Record<string, string | number>) => string translate: (key: string, vars?: Record<string, string | number>) => string
getSdk: (directory: string) => OpencodeClient
}) { }) {
const children: Record<string, [Store<State>, SetStoreFunction<State>]> = {} const children: Record<string, [Store<State>, SetStoreFunction<State>]> = {}
const vcsCache = new Map<string, VcsCache>() const vcsCache = new Map<string, VcsCache>()
@@ -154,16 +158,34 @@ export function createChildStoreManager(input: {
const init = () => const init = () =>
createRoot((dispose) => { createRoot((dispose) => {
const sdk = input.getSdk(directory)
const initialMeta = meta[0].value const initialMeta = meta[0].value
const initialIcon = icon[0].value const initialIcon = icon[0].value
const [pathQuery, mcpQuery, lspQuery, providerQuery] = useQueries(() => ({
queries: [
loadPathQuery(directory, sdk),
loadMcpQuery(directory, sdk),
loadLspQuery(directory, sdk),
loadProvidersQuery(directory, sdk),
],
}))
const child = createStore<State>({ const child = createStore<State>({
project: "", project: "",
projectMeta: initialMeta, projectMeta: initialMeta,
icon: initialIcon, icon: initialIcon,
provider_ready: false, get provider_ready() {
return providerQuery.isLoading
},
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: [],
@@ -174,10 +196,18 @@ export function createChildStoreManager(input: {
todo: {}, todo: {},
permission: {}, permission: {},
question: {}, question: {},
mcp_ready: false, get mcp_ready() {
mcp: {}, return mcpQuery.isLoading
lsp_ready: false, },
lsp: [], get mcp() {
return mcpQuery.isLoading ? {} : (mcpQuery.data ?? {})
},
get lsp_ready() {
return lspQuery.isLoading
},
get lsp() {
return lspQuery.isLoading ? [] : (lspQuery.data ?? [])
},
vcs: vcsStore.value, vcs: vcsStore.value,
limit: 5, limit: 5,
message: {}, message: {},
@@ -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(
+9 -32
View File
@@ -391,37 +391,14 @@ 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 // Preserve local icon override from per-workspace localStorage cache (childStore.icon).
const localOverride = // Without this, different subdirectories of the same git repo would share the same
local?.name !== undefined || // icon from the database instead of using their individual overrides.
local?.commands?.start !== undefined || const base = { ...metadata, ...project }
local?.icon?.override !== undefined || if (childStore.icon) {
local?.icon?.color !== undefined return { ...base, icon: { ...base.icon, override: childStore.icon } }
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,
},
} }
return base
} }
const roots = createMemo(() => { const roots = createMemo(() => {
@@ -516,7 +493,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 +559,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":
+23 -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",
@@ -727,6 +728,11 @@ export const dict = {
"settings.general.row.language.title": "Language", "settings.general.row.language.title": "Language",
"settings.general.row.language.description": "Change the display language for OpenCode", "settings.general.row.language.description": "Change the display language for OpenCode",
"settings.general.row.shell.title": "Terminal Shell",
"settings.general.row.shell.description":
"Choose the shell used for your terminal. Compatible shells are also used for agent tool calls.",
"settings.general.row.shell.autoDefault": "Auto (Default)",
"settings.general.row.shell.terminalOnly": "terminal only",
"settings.general.row.appearance.title": "Appearance", "settings.general.row.appearance.title": "Appearance",
"settings.general.row.appearance.description": "Customise how OpenCode looks on your device", "settings.general.row.appearance.description": "Customise how OpenCode looks on your device",
"settings.general.row.colorScheme.title": "Color scheme", "settings.general.row.colorScheme.title": "Color scheme",
@@ -734,13 +740,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 +767,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 -4
View File
@@ -1,5 +1,3 @@
import { dict as en } from "./en"
export const dict = { export const dict = {
"command.category.suggested": "추천", "command.category.suggested": "추천",
"command.category.view": "보기", "command.category.view": "보기",
@@ -211,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": "댓글 요약…",
@@ -568,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": "후속 조치 동작",
@@ -583,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"
+26 -21
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!()
}, },
}, },
{ {
@@ -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 -143
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,7 +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 canReview = createMemo(() => !!sync.project) const canReview = createMemo(() => !!sync.project)
const reviewTab = createMemo(() => isDesktop()) const reviewTab = createMemo(() => isDesktop())
const tabState = createSessionTabs({ const tabState = createSessionTabs({
@@ -484,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(
@@ -518,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<{
@@ -571,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()
@@ -663,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"
@@ -805,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
@@ -817,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
@@ -835,7 +783,9 @@ export default function Page() {
}) })
}, 0) }, 0)
}) })
}),
return sync.session.sync(id)
},
) )
createEffect( createEffect(
@@ -897,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 =
@@ -1051,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
@@ -1066,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 },
), ),
@@ -1882,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 -1
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"
+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()
}) })
} }
@@ -15,8 +15,8 @@ import { ScrollView } from "@opencode-ai/ui/scroll-view"
import { TextField } from "@opencode-ai/ui/text-field" import { TextField } from "@opencode-ai/ui/text-field"
import type { AssistantMessage, Message as MessageType, Part, TextPart, UserMessage } from "@opencode-ai/sdk/v2" import type { AssistantMessage, Message as MessageType, Part, TextPart, UserMessage } from "@opencode-ai/sdk/v2"
import { showToast } from "@opencode-ai/ui/toast" import { showToast } from "@opencode-ai/ui/toast"
import { Binary } from "@opencode-ai/shared/util/binary" import { Binary } from "@opencode-ai/core/util/binary"
import { getFilename } from "@opencode-ai/shared/util/path" import { getFilename } from "@opencode-ai/core/util/path"
import { Popover as KobaltePopover } from "@kobalte/core/popover" import { Popover as KobaltePopover } from "@kobalte/core/popover"
import { shouldMarkBoundaryGesture, normalizeWheelDelta } from "@/pages/session/message-gesture" import { shouldMarkBoundaryGesture, normalizeWheelDelta } from "@/pages/session/message-gesture"
import { SessionContextUsage } from "@/components/session-context-usage" import { SessionContextUsage } from "@/components/session-context-usage"
@@ -259,7 +259,7 @@ export function MessageTimeline(props: {
if (!id) return idle if (!id) return idle
return sync.data.session_status[id] ?? idle return sync.data.session_status[id] ?? idle
}) })
const working = createMemo(() => !!pending() || sessionStatus().type !== "idle") const working = createMemo(() => sessionStatus().type !== "idle")
const tint = createMemo(() => messageAgentColor(sessionMessages(), sync.data.agent)) const tint = createMemo(() => messageAgentColor(sessionMessages(), sync.data.agent))
const [timeoutDone, setTimeoutDone] = createSignal(true) const [timeoutDone, setTimeoutDone] = createSignal(true)
@@ -721,7 +721,7 @@ export function MessageTimeline(props: {
"md:max-w-200 md:mx-auto 2xl:max-w-[1000px]": props.centered, "md:max-w-200 md:mx-auto 2xl:max-w-[1000px]": props.centered,
}} }}
> >
<Show when={workingStatus() !== "hidden"}> <Show when={workingStatus() !== "hidden" && settings.general.showSessionProgressBar()}>
<div <div
data-component="session-progress" data-component="session-progress"
data-state={workingStatus()} data-state={workingStatus()}
@@ -812,7 +812,7 @@ export function MessageTimeline(props: {
</Show> </Show>
</div> </div>
</div> </div>
<Show when={sessionID()}> <Show when={sessionID()} keyed>
{(id) => ( {(id) => (
<div class="shrink-0 flex items-center gap-3"> <div class="shrink-0 flex items-center gap-3">
<SessionContextUsage placement="bottom" /> <SessionContextUsage placement="bottom" />
@@ -878,12 +878,12 @@ export function MessageTimeline(props: {
</DropdownMenu.ItemLabel> </DropdownMenu.ItemLabel>
</DropdownMenu.Item> </DropdownMenu.Item>
</Show> </Show>
<DropdownMenu.Item onSelect={() => void archiveSession(id())}> <DropdownMenu.Item onSelect={() => void archiveSession(id)}>
<DropdownMenu.ItemLabel>{language.t("common.archive")}</DropdownMenu.ItemLabel> <DropdownMenu.ItemLabel>{language.t("common.archive")}</DropdownMenu.ItemLabel>
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Separator /> <DropdownMenu.Separator />
<DropdownMenu.Item <DropdownMenu.Item
onSelect={() => dialog.show(() => <DialogDeleteSession sessionID={id()} />)} onSelect={() => dialog.show(() => <DialogDeleteSession sessionID={id} />)}
> >
<DropdownMenu.ItemLabel>{language.t("common.delete")}</DropdownMenu.ItemLabel> <DropdownMenu.ItemLabel>{language.t("common.delete")}</DropdownMenu.ItemLabel>
</DropdownMenu.Item> </DropdownMenu.Item>
@@ -19,6 +19,9 @@ import { useCommand } from "@/context/command"
import { useFile, type SelectedLineRange } from "@/context/file" import { useFile, type SelectedLineRange } from "@/context/file"
import { useLanguage } from "@/context/language" import { useLanguage } from "@/context/language"
import { useLayout } from "@/context/layout" import { useLayout } from "@/context/layout"
import { usePlatform } from "@/context/platform"
import { useSettings } from "@/context/settings"
import { useSync } from "@/context/sync"
import { createFileTabListSync } from "@/pages/session/file-tab-scroll" import { createFileTabListSync } from "@/pages/session/file-tab-scroll"
import { FileTabContent } from "@/pages/session/file-tabs" import { FileTabContent } from "@/pages/session/file-tabs"
import { createOpenSessionFileTab, createSessionTabs, getTabReorderIndex, type Sizing } from "@/pages/session/helpers" import { createOpenSessionFileTab, createSessionTabs, getTabReorderIndex, type Sizing } from "@/pages/session/helpers"
@@ -39,6 +42,9 @@ export function SessionSidePanel(props: {
size: Sizing size: Sizing
}) { }) {
const layout = useLayout() const layout = useLayout()
const platform = usePlatform()
const settings = useSettings()
const sync = useSync()
const file = useFile() const file = useFile()
const language = useLanguage() const language = useLanguage()
const command = useCommand() const command = useCommand()
@@ -46,9 +52,15 @@ export function SessionSidePanel(props: {
const { sessionKey, tabs, view } = useSessionLayout() const { sessionKey, tabs, view } = useSessionLayout()
const isDesktop = createMediaQuery("(min-width: 768px)") const isDesktop = createMediaQuery("(min-width: 768px)")
const shown = createMemo(
() =>
platform.platform !== "desktop" ||
import.meta.env.VITE_OPENCODE_CHANNEL !== "beta" ||
settings.general.showFileTree(),
)
const reviewOpen = createMemo(() => isDesktop() && view().reviewPanel.opened()) const reviewOpen = createMemo(() => isDesktop() && view().reviewPanel.opened())
const fileOpen = createMemo(() => isDesktop() && layout.fileTree.opened()) const fileOpen = createMemo(() => isDesktop() && shown() && layout.fileTree.opened())
const open = createMemo(() => reviewOpen() || fileOpen()) const open = createMemo(() => reviewOpen() || fileOpen())
const reviewTab = createMemo(() => isDesktop()) const reviewTab = createMemo(() => isDesktop())
const panelWidth = createMemo(() => { const panelWidth = createMemo(() => {
@@ -341,6 +353,7 @@ export function SessionSidePanel(props: {
</div> </div>
</div> </div>
<Show when={shown()}>
<div <div
id="file-tree-panel" id="file-tree-panel"
aria-hidden={!fileOpen()} aria-hidden={!fileOpen()}
@@ -398,7 +411,6 @@ export function SessionSidePanel(props: {
/> />
</Show> </Show>
</Match> </Match>
<Match when={true}>{empty(props.empty())}</Match>
</Switch> </Switch>
</Tabs.Content> </Tabs.Content>
<Tabs.Content value="all" class="bg-background-stronger px-3 py-0"> <Tabs.Content value="all" class="bg-background-stronger px-3 py-0">
@@ -433,6 +445,7 @@ export function SessionSidePanel(props: {
</div> </div>
</Show> </Show>
</div> </div>
</Show>
</div> </div>
</aside> </aside>
</Show> </Show>
@@ -7,12 +7,14 @@ import { useLanguage } from "@/context/language"
import { useLayout } from "@/context/layout" import { useLayout } from "@/context/layout"
import { useLocal } from "@/context/local" import { useLocal } from "@/context/local"
import { usePermission } from "@/context/permission" import { usePermission } from "@/context/permission"
import { usePlatform } from "@/context/platform"
import { usePrompt } from "@/context/prompt" import { usePrompt } from "@/context/prompt"
import { useSDK } from "@/context/sdk" import { useSDK } from "@/context/sdk"
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 { showToast } from "@opencode-ai/ui/toast" import { showToast } from "@opencode-ai/ui/toast"
import { findLast } from "@opencode-ai/shared/util/array" import { findLast } from "@opencode-ai/core/util/array"
import { createSessionTabs } from "@/pages/session/helpers" import { createSessionTabs } from "@/pages/session/helpers"
import { extractPromptFromParts } from "@/utils/prompt" import { extractPromptFromParts } from "@/utils/prompt"
import { UserMessage } from "@opencode-ai/sdk/v2" import { UserMessage } from "@opencode-ai/sdk/v2"
@@ -39,8 +41,10 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
const language = useLanguage() const language = useLanguage()
const local = useLocal() const local = useLocal()
const permission = usePermission() const permission = usePermission()
const platform = usePlatform()
const prompt = usePrompt() const prompt = usePrompt()
const sdk = useSDK() const sdk = useSDK()
const settings = useSettings()
const sync = useSync() const sync = useSync()
const terminal = useTerminal() const terminal = useTerminal()
const layout = useLayout() const layout = useLayout()
@@ -66,6 +70,10 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
}) })
const activeFileTab = tabState.activeFileTab const activeFileTab = tabState.activeFileTab
const closableTab = tabState.closableTab const closableTab = tabState.closableTab
const shown = () =>
platform.platform !== "desktop" ||
import.meta.env.VITE_OPENCODE_CHANNEL !== "beta" ||
settings.general.showFileTree()
const idle = { type: "idle" as const } const idle = { type: "idle" as const }
const status = () => sync.data.session_status[params.id ?? ""] ?? idle const status = () => sync.data.session_status[params.id ?? ""] ?? idle
@@ -457,12 +465,16 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
keybind: "mod+shift+r", keybind: "mod+shift+r",
onSelect: () => view().reviewPanel.toggle(), onSelect: () => view().reviewPanel.toggle(),
}), }),
...(shown()
? [
viewCommand({ viewCommand({
id: "fileTree.toggle", id: "fileTree.toggle",
title: language.t("command.fileTree.toggle"), title: language.t("command.fileTree.toggle"),
keybind: "mod+\\", keybind: "mod+\\",
onSelect: () => layout.fileTree.toggle(), onSelect: () => layout.fileTree.toggle(),
}), }),
]
: []),
viewCommand({ viewCommand({
id: "input.focus", id: "input.focus",
title: language.t("command.input.focus"), title: language.t("command.input.focus"),
+1 -1
View File
@@ -1,4 +1,4 @@
import { base64Decode } from "@opencode-ai/shared/util/encode" import { base64Decode } from "@opencode-ai/core/util/encode"
export function decode64(value: string | undefined) { export function decode64(value: string | undefined) {
if (value === undefined) return if (value === undefined) return

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