Compare commits

...
Author SHA1 Message Date
Kit LangtonandGitHub ae2ecd1ed3 Migrate custom provider tests to instance fixtures
Migrate the next custom provider/model config tests to Effect-aware instance fixtures while keeping timing neutral and behavior unchanged.
2026-05-18 17:49:26 +00:00
Kit LangtonandGitHub 159d271e1e refactor(sync): publish via EffectBridge.fork for codebase consistency (#28187) 2026-05-18 13:30:41 -04:00
Kit LangtonandGitHub 762850dfe5 Migrate provider config tests to instance fixtures
Convert the first provider env/config/filtering tests to Effect-aware instance fixtures while keeping behavior unchanged and documenting neutral timing.
2026-05-18 13:22:59 -04:00
Kit LangtonandGitHub b039702e8c feat(tui): add syntax highlighting for elixir, fsharp, r, make, vim, xml, agda (#28198) 2026-05-18 13:08:08 -04:00
opencode-agent[bot] 094886c848 chore: generate 2026-05-18 17:03:44 +00:00
Shoubhit DashandGitHub dc0297f4ac refactor(session): extract reference prompt helpers (#28197) 2026-05-18 22:32:18 +05:30
Kit LangtonandGitHub 3ab67f3280 Stabilize watcher test readiness (#28194) 2026-05-18 12:51:46 -04:00
Shoubhit DashandGitHub a2e6bd503b refactor(reference): split materialization state (#28190) 2026-05-18 22:14:33 +05:30
Aiden ClineandGitHub 05ac345696 refactor(session): move prompt reminders out of core loop (#28082) 2026-05-18 11:36:38 -05:00
opencode-agent[bot] e3feca09b3 chore: generate 2026-05-18 16:20:46 +00:00
Kit LangtonandGitHub 896ad7b884 Speed up targeted opencode tests
Reduce avoidable setup costs in slow opencode tests while preserving reviewed coverage and recording the benchmark evidence for follow-up test-suite work.
2026-05-18 16:18:29 +00:00
opencode-agent[bot] 0a945219a9 chore: generate 2026-05-18 16:17:46 +00:00
Shoubhit DashandGitHub 94828eb44b refactor(repository): type cache failures (#28188) 2026-05-18 21:46:18 +05:30
Shoubhit DashandGitHub 96192495ae refactor(repository): add cache service (#28184) 2026-05-18 21:25:38 +05:30
opencode-agent[bot] f7b5576bcc chore: generate 2026-05-18 15:39:33 +00:00
Kit LangtonandGitHub cb35493242 fix(bus): acquire PubSub subscription eagerly to close /event race (#27959) 2026-05-18 11:38:05 -04:00
Shoubhit DashandGitHub 5bfd7fd16c refactor(repository): clarify reference domain (#28182) 2026-05-18 21:04:44 +05:30
opencode-agent[bot] 2932b41e64 chore: generate 2026-05-18 15:14:13 +00:00
Shoubhit DashandGitHub eb389c58eb refactor(reference): normalize config entries (#28178) 2026-05-18 20:42:41 +05:30
Shoubhit DashandGitHub 54ff0a669b test(reference): cover configured reference contracts (#28170) 2026-05-18 20:09:27 +05:30
opencode-agent[bot] e56999fd36 chore: generate 2026-05-18 12:31:37 +00:00
Simon KleeandGitHub 1124315267 run: refresh prompt layout after paste (#28164)
Pasting into the prompt textarea left its layout stale until the next edit, so the visible content did not reflect the pasted text. Mark the layout dirty on paste and notify the content-change handler once the renderer is idle so the prompt updates immediately.
2026-05-18 12:30:20 +00:00
opencode-agent[bot] 2bf3f3041f chore: update nix node_modules hashes 2026-05-18 12:03:51 +00:00
SebastianandGitHub 6e4db5666a upgrade opentui to 0.2.14 (#28090) 2026-05-18 13:44:08 +02:00
Shoubhit DashandGitHub 564cde393e fix(tui): copy pasted prompt content (#28156) 2026-05-18 17:02:34 +05:30
opencode-agent[bot] c813927bb6 chore: generate 2026-05-18 11:07:52 +00:00
Simon KleeandGitHub 5970c12d90 run: replay session history on interactive resume (#26880) 2026-05-18 13:06:27 +02:00
opencode-agent[bot] 116a4e33ba chore: generate 2026-05-18 11:06:05 +00:00
Shoubhit DashandGitHub 611e48c4ac fix(tui): collapse long tool output lines (#28148) 2026-05-18 16:34:34 +05:30
Brendan AllanandGitHub 836a33198e fix(ui): fix question dock overflow and message part flex layout (#28142) 2026-05-18 17:55:27 +08:00
opencode-agent[bot] 7afd477d1a chore: generate 2026-05-18 09:28:20 +00:00
fe143df151 fix(ui): fallback to execCommand for clipboard copy when navigator.clipboard fails (#27993)
Co-authored-by: SpiritChen51 <spiritchen51@users.noreply.github.com>
2026-05-18 17:26:45 +08:00
e94aecaa08 fix(tui): use contrast-aware foreground for paste summary badge (#27969)
Co-authored-by: Simon Klee <hello@simonklee.dk>
2026-05-18 08:38:40 +00:00
Brendan AllanandGitHub 418c0ea04a feat(desktop): add notification permission for renderer (#28119) 2026-05-18 15:43:28 +08:00
opencode-agent[bot] 4312e5df05 chore: generate 2026-05-18 07:21:25 +00:00
Brendan AllanandGitHub f80f3e33ec desktop: add free limit + go usage exceeded dialogs to match tui (#27677) 2026-05-18 15:20:08 +08:00
opencode-agent[bot] 479206449e chore: generate 2026-05-18 06:41:17 +00:00
6849059b00 fix(app): hide prompt placeholder for whitespace input (#28101)
Co-authored-by: ShrootBuck <ShrootBuck@users.noreply.github.com>
2026-05-18 14:39:51 +08:00
opencode-agent[bot] 43df145cd2 chore: update nix node_modules hashes 2026-05-18 03:59:28 +00:00
Frank 28a0bf6c8f sync 2026-05-17 23:43:23 -04:00
opencode-agent[bot] 30e4edffd5 chore: generate 2026-05-18 03:42:06 +00:00
5452ab6db7 perf(app): virtualize session timeline rows (#26949)
Co-authored-by: Brendan Allan <git@brendonovich.dev>
2026-05-18 03:40:52 +00:00
DaxandGitHub e85119aa64 Load models.dev snapshot from build global (#28077) 2026-05-17 21:59:44 -04:00
黑墨水鱼andGitHub 71b27a1b0f fix: sync PWA status bar theme-color with app color scheme (#28006) 2026-05-18 00:12:02 +00:00
opencode-agent[bot] 32f37d86f0 chore: update nix node_modules hashes 2026-05-17 23:40:17 +00:00
opencode-agent[bot] b14ea406ba chore: generate 2026-05-17 23:25:50 +00:00
Luke ParkerandGitHub de846ca57d chore: Upgrade Bun to the final non-rust version (#27648) 2026-05-18 09:24:26 +10:00
Luke ParkerandGitHub f06b78751e fix(desktop): install the latest available update (#27953) 2026-05-18 09:23:32 +10:00
opencode-agent[bot] 969d0f48b2 chore: generate 2026-05-17 23:03:12 +00:00
Luke ParkerandGitHub fc19dcc70c fix: sort v2 session list by updated time (#27954) 2026-05-18 09:01:55 +10:00
opencode-agent[bot] 49c6b46afc chore: update nix node_modules hashes 2026-05-17 22:39:36 +00:00
SebastianandGitHub f97e115ee2 dialog prompt submit keybind + opentui event sink (#27945) 2026-05-18 00:23:19 +02:00
Dax Raad e92b1fe7d7 core: let models layer infer its own type so layer composition no longer requires matching explicit requirements 2026-05-17 17:37:11 -04:00
opencode f98449c9b5 sync release versions for v1.15.4 2026-05-17 17:44:50 +00:00
Frank 468eb68878 zen: update monitoring query 2026-05-17 13:15:39 -04:00
DaxandGitHub 23b594de6e fix: preserve bus instance context (#28051) 2026-05-17 12:56:42 -04:00
Frank 5060577ee1 sync 2026-05-17 12:37:47 -04:00
Aiden ClineGitHubopencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>rekram1-node
d3ebb1f7c0 ignore: cleanup readme (#28049)
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-05-17 11:26:23 -05:00
Shoubhit DashandGitHub e4cc4e1682 fix(lsp): preserve instance ref for update events (#28016) 2026-05-17 16:37:00 +05:30
opencode-agent[bot] 53e89f9d52 chore: generate 2026-05-17 08:06:12 +00:00
Frank de247b7aae sync 2026-05-17 04:04:39 -04:00
Frank 0b8050d453 sync 2026-05-17 01:59:20 -04:00
be6a89a3b8 docs: update README.es.md (#27739)
Co-authored-by: Victor Navarro <vn4varro@gmail.com>
2026-05-16 19:33:24 +02:00
Kit LangtonandGitHub c0a8b509c7 style(tui): distinguish markdown h1 headings (#27814) 2026-05-16 11:18:17 -04:00
opencode f80651fa91 sync release versions for v1.15.3 2026-05-16 14:07:33 +00:00
Shoubhit DashandGitHub 68af95390d fix: hide task background instructions by default (#27872) 2026-05-16 19:18:15 +05:30
opencode-agent[bot] 321db7a819 chore: generate 2026-05-16 13:27:23 +00:00
Dax Raad 6d2219e001 fix(cli): preserve instance context in async commands 2026-05-16 09:25:45 -04:00
opencode-agent[bot] dd432e3cde chore: generate 2026-05-16 13:21:57 +00:00
Dax Raad 77db212a0a fix read stream byte cap 2026-05-16 09:20:35 -04:00
opencode f56263791c sync release versions for v1.15.2 2026-05-16 12:53:10 +00:00
Dax Raad 88363f1ed9 fixed issue in opencode run 2026-05-16 08:27:25 -04:00
JackandGitHub c5db39f626 Remove Ring 2.6 1T from Zen docs (#27849) 2026-05-16 17:55:32 +08:00
vimtor b5aed287ca chore: reduce alerts noise 2026-05-16 09:39:13 +02:00
DaxandGitHub 53849bd866 fix(sync): publish events on injected project bus (#27825) 2026-05-16 05:56:49 +00:00
opencode e33912bfee sync release versions for v1.15.1 2026-05-16 05:44:44 +00:00
Aiden ClineandGitHub 548648a3d9 core: reduce prompts for shell, todowrite, and task tools (#26821) 2026-05-16 00:18:47 -05:00
Caleb NortonandGitHub 4643e13170 feat(nix): add opencode-electron derivation (#16163) 2026-05-15 23:20:48 -05:00
Dax Raad 042e6a5c86 tui: newly pinned sessions now append to the end of the list instead of jumping to the top 2026-05-15 23:57:40 -04:00
Dax Raad e36d6a0cbe core: clarify postinstall error message when binary is missing
Users installing with pnpm or --ignore-scripts now see a clear explanation
of why the native binary is missing and exact steps to fix it. The shell
script wrapper provides more actionable guidance than the previous Node.js
fallback that only suggested running the postinstall script without context
about why it wasn't run automatically.
2026-05-15 23:12:00 -04:00
SebastianandGitHub cc9c0b15c7 Revert "add dialog prompt submit keybind (#27807)" (#27815) 2026-05-16 04:44:32 +02:00
Kit LangtonandGitHub f3b0d3d7ac fix(tui): dedupe consecutive prompt history entries (#27816) 2026-05-16 02:36:35 +00:00
opencode-agent[bot] 764c6bc517 chore: update nix node_modules hashes 2026-05-16 01:20:56 +00:00
SebastianandGitHub d441e931f9 add dialog prompt submit keybind (#27807) 2026-05-16 03:11:46 +02:00
SebastianandGitHub ad79ad9ea8 upgrade opentui to 0.2.11 (#27808) 2026-05-16 03:05:54 +02:00
opencode-agent[bot] d6b23fd8f6 chore: generate 2026-05-16 00:44:10 +00:00
Kit LangtonandGitHub 5911bd532d fix(tui): show config error details on startup (#27803) 2026-05-15 20:42:56 -04:00
Dax Raad 2385123f03 Fix thinking toggle defaults 2026-05-15 20:27:36 -04:00
DaxandGitHub 09549661e1 Fix npm CLI binary installation (#27801) 2026-05-15 18:43:37 -04:00
opencode-agent[bot] da495fd2e0 chore: generate 2026-05-15 22:09:43 +00:00
vimtor 85cd447910 chore: reduce alerts noise 2026-05-16 00:07:59 +02:00
SebastianandGitHub 0f31fd631b Fix multiline mentions (#27649) 2026-05-15 23:04:20 +02:00
SebastianandGitHub aa07e21945 handle undefined tips (#27635) 2026-05-15 23:04:00 +02:00
Shoubhit DashandGitHub f060874b29 feat(tui): add minimal thinking mode with click-to-expand (#27623) 2026-05-16 02:09:58 +05:30
vimtor f21c582db9 chore: reduce alerting noise 2026-05-15 22:18:50 +02:00
Shoubhit DashandGitHub 65f96a5851 refactor(instance): retire WithInstance adapter (#27782) 2026-05-16 01:30:07 +05:30
Aiden ClineandGitHub 48122b31cc fix(tool): bridge custom tool zod metadata (#27770) 2026-05-15 14:50:21 -05:00
opencode-agent[bot] 0df2f5b45f chore: generate 2026-05-15 19:48:45 +00:00
Shoubhit DashandGitHub 499e8e4b78 test(instance): add effect-native fixture helpers (#27781) 2026-05-16 01:17:37 +05:30
Shoubhit DashandGitHub f33b4455a1 feat(tui): enable pinned session switching (#27780) 2026-05-16 01:10:16 +05:30
Shoubhit DashandGitHub a24abd2b11 refactor(lsp): require explicit instance context (#27767) 2026-05-16 00:46:27 +05:30
opencode-agent[bot] d44bef2107 chore: generate 2026-05-15 18:45:24 +00:00
Shoubhit DashandGitHub f99339e525 fix(tui): keep session switching pinned-only (#27775) 2026-05-16 00:14:07 +05:30
Shoubhit DashandGitHub 2b0e72ab79 refactor(workspace): centralize adapter invocation (#27768) 2026-05-15 23:59:01 +05:30
Shoubhit DashandGitHub 2fdee50b3b refactor(acp): extract runtime reentry (#27769) 2026-05-15 23:58:52 +05:30
opencode-agent[bot] 48293c5271 chore: generate 2026-05-15 17:37:07 +00:00
Shoubhit DashandGitHub 0c9cfe923f refactor(instance): remove legacy runtime fallback (#27757) 2026-05-15 23:05:44 +05:30
opencode-agent[bot] 9975c1ed1c chore: generate 2026-05-15 15:12:20 +00:00
ef7d801271 fix(tool): preserve custom tool arg descriptions (#27750)
Co-authored-by: khimaros <231498+khimaros@users.noreply.github.com>
2026-05-15 10:11:01 -05:00
opencode-agent[bot] eb630075c3 chore: generate 2026-05-15 15:01:55 +00:00
Shoubhit DashandGitHub a2392ca60d refactor(worktree): provide runtime reentry refs (#27754) 2026-05-15 20:30:29 +05:30
opencode-agent[bot] f9371eb66c chore: generate 2026-05-15 14:36:04 +00:00
Shoubhit DashandGitHub fa9a2cb24d refactor(instance): remove remaining bind call sites (#27731) 2026-05-15 20:04:42 +05:30
Victor NavarroandGitHub 2d90f325fc ci: catch provider errors across all opencode tiers (#27495) 2026-05-15 16:31:59 +02:00
Aiden ClineandGitHub c2ffd7cf14 fix: markdown table rendering (#27747) 2026-05-15 09:22:24 -05:00
vimtor 104f5d5a14 chore: exclude provider from triggers 2026-05-15 16:01:11 +02:00
Shoubhit DashandGitHub 1c7c03332e test(workspace): avoid legacy instance reads (#27727) 2026-05-15 17:07:21 +05:30
opencode-agent[bot] 984eefa6f8 chore: generate 2026-05-15 11:02:14 +00:00
Shoubhit DashandGitHub bf64f8cbb5 refactor(cli): dispose bootstrap instance explicitly (#27721) 2026-05-15 16:30:54 +05:30
opencode-agent[bot] 727a83aa7a chore: generate 2026-05-15 10:46:06 +00:00
Shoubhit DashandGitHub e65383810a refactor(tool): read repo overview directory from instance state (#27717) 2026-05-15 16:14:49 +05:30
Shoubhit DashandGitHub 12b666e2c9 refactor(project): import instance context directly (#27714) 2026-05-15 15:59:56 +05:30
Shoubhit DashandGitHub eb5ef1c073 refactor(flags): remove unused flag exports (#27709) 2026-05-15 15:35:24 +05:30
Shoubhit DashandGitHub 356f684186 refactor(flags): migrate skip migrations flag (#27705) 2026-05-15 14:54:29 +05:30
Shoubhit DashandGitHub 7b370406a9 refactor(flags): migrate lsp download flag (#27699) 2026-05-15 14:35:31 +05:30
Shoubhit DashandGitHub 202cc863b4 refactor(flags): migrate claude code prompt flag (#27690) 2026-05-15 14:17:04 +05:30
Shoubhit DashandGitHub 22cb0395e2 refactor(flags): migrate external skills flag (#27685) 2026-05-15 13:24:56 +05:30
Shoubhit DashandGitHub 2d6bedecd4 refactor(flags): migrate output token max to runtime flags (#27680) 2026-05-15 13:07:35 +05:30
opencode-agent[bot] 2080390ca6 chore: generate 2026-05-15 07:36:10 +00:00
1ac3f09468 fix(watcher): resolve symlinked .git path before subscribing (#27016)
Co-authored-by: Simon Klee <hello@simonklee.dk>
2026-05-15 09:34:53 +02:00
Aiden ClineandGitHub ca8f578f2f ci: skip previously cleaned PRs (#27670) 2026-05-15 00:23:09 -05:00
Aiden ClineandGitHub d59d99665b ci: Automate PR cleanup (#27667) 2026-05-14 23:47:59 -05:00
opencode c43edc5b71 sync release versions for v1.15.0 2026-05-15 04:03:54 +00:00
Dax Raad 7a012cac08 fix(tool): ignore invalid custom tool exports 2026-05-14 23:36:28 -04:00
James LongandGitHub af06e52708 fix(session): ignore instruction lookup errors (#27656) 2026-05-14 23:12:30 -04:00
Dax Raad f807152724 core: fix event projector lookup to use versioned type keys
Fixes a bug where projectors were stored with Definition object references
as Map keys but lookups were failing due to object identity mismatches.
Now uses versioned type strings as keys, ensuring events are correctly
matched to their projectors during sync processing.

This fixes issues where certain events would not be properly projected
to the read model, causing stale or missing data in views.
2026-05-14 22:52:03 -04:00
Dax Raad b0ea7a5aa7 more test fixes 2026-05-14 22:45:09 -04:00
opencode-agent[bot] 34b1be5bcd chore: generate 2026-05-15 02:34:06 +00:00
Dax Raad 16639eee76 test fixes 2026-05-14 22:32:38 -04:00
opencode-agent[bot] 10c8493940 chore: generate 2026-05-15 02:14:56 +00:00
Dax Raad a50ff72f3f fix: remove debug logging 2026-05-14 22:13:15 -04:00
Dax Raad 5f4e5e6896 more typecheck fixes 2026-05-14 22:05:12 -04:00
Dax Raad f39cf911d7 fix missing event types in sdk 2026-05-14 21:57:25 -04:00
Brendan AllanandGitHub f179dcbf02 fix(app): only run session.updated archive logic if archive state changes (#27637) 2026-05-15 09:42:47 +08:00
opencode-agent[bot] fd6a8520b8 chore: generate 2026-05-15 00:52:06 +00:00
DaxandGitHub e11e089e42 Add Effect-native core event system (#27415) 2026-05-15 00:50:23 +00:00
Luna SeemannandGitHub 73cdba959b feat(desktop): auto-hide menu bar on Linux and Windows (#27618) 2026-05-15 08:48:29 +08:00
opencode 4e7a60dac6 sync release versions for v1.14.51 2026-05-15 00:39:54 +00:00
opencode-agent[bot] e62ebd8fec chore: generate 2026-05-15 00:02:04 +00:00
Kit LangtonandGitHub 195f592640 refactor(server): simplify listener lifecycle (#27413) 2026-05-15 00:00:52 +00:00
opencode-agent[bot] 78769010a1 chore: generate 2026-05-14 23:46:57 +00:00
Kit LangtonandGitHub 4e143e3a3e test(lib): promote pollWithTimeout/awaitWithTimeout helpers (#27626) 2026-05-14 23:45:32 +00:00
opencode-agent[bot] dab567aa2d chore: generate 2026-05-14 23:34:42 +00:00
Kit LangtonandGitHub 9d35b04e13 test(acp): replace fixed sleeps with pollUntil in event-subscription (#27624) 2026-05-14 23:33:06 +00:00
Kit LangtonandGitHub 273ab56949 test(bus): fix flaky subscriber races with readiness latch (#27625) 2026-05-14 19:32:25 -04:00
Kit LangtonandGitHub 302ba0ca0b test(session): de-flake shell-cancel tests by waiting for busy state (#27622) 2026-05-14 19:24:09 -04:00
Shoubhit DashandGitHub d35e09f1fc test(workspace): use runtime flags in workspace tests (#27612) 2026-05-15 04:19:39 +05:30
Shoubhit DashandGitHub fc34c74567 refactor(flags): move channel db flag to runtime flags (#27615) 2026-05-15 04:09:10 +05:30
Shoubhit DashandGitHub cb4f5cdea9 refactor(flags): move auto share to runtime flags (#27611) 2026-05-15 03:58:26 +05:30
nv-kasikritcandGitHub d34a0194ec feat(provider): add NVIDIA endpoints origin header (#27394) 2026-05-14 17:21:58 -05:00
Shoubhit DashandGitHub 43310f4d8c refactor(flags): move embedded web ui flag to runtime flags (#27613) 2026-05-15 03:51:29 +05:30
Shoubhit DashandGitHub e22cfa435a refactor(lsp): move ty flag to runtime flags (#27610) 2026-05-15 03:40:30 +05:30
opencode-agent[bot] 93b1ccc029 chore: generate 2026-05-14 22:00:48 +00:00
Shoubhit DashandGitHub faca2b90c1 refactor(flags): migrate icon discovery runtime flag (#27609) 2026-05-15 03:24:14 +05:30
Shoubhit DashandGitHub 76ff18afde refactor(format): move oxfmt flag to runtime flags (#27608) 2026-05-15 03:03:37 +05:30
opencode-agent[bot] 9914c9af17 chore: generate 2026-05-14 21:32:52 +00:00
Shoubhit DashandGitHub f202226bbc refactor(flags): move bash timeout to runtime flags (#27607) 2026-05-15 02:49:14 +05:30
Shoubhit DashandGitHub 34198f422c refactor(provider): use runtime flag for experimental models (#27606) 2026-05-15 02:48:01 +05:30
Shoubhit DashandGitHub cccdeef294 refactor(flags): migrate claude code skills flag to RuntimeFlags (#27605) 2026-05-15 02:47:26 +05:30
MusaandGitHub 83c145f889 fix(plugin): scope digitalocean oauth to genai (#27599) 2026-05-14 15:20:34 -05:00
Kit LangtonandGitHub d353a6bc24 fix(worktree): accept missing create payload (#27582) 2026-05-14 14:25:22 -04:00
bo-tatoandGitHub d25cc42d21 docs(app): stale reference to removed multi-edit tool (#27579) 2026-05-14 13:10:01 -05:00
opencode-agent[bot] 6039b894c5 chore: generate 2026-05-14 18:05:32 +00:00
Kit LangtonandGitHub b4fc5ef071 refactor(http-recorder): tighten cassette safety, fix WS leaks + docs (#26730) 2026-05-14 18:03:22 +00:00
opencode-agent[bot] f6c8e35383 chore: generate 2026-05-14 17:58:35 +00:00
Kit LangtonandGitHub 94564f3588 fix(session): prevent double auto-compaction from filterCompacted reorder (#27545) 2026-05-14 13:56:12 -04:00
Kit LangtonandGitHub 855bda8384 test(question): wait on question events (#27124) 2026-05-14 13:23:47 -04:00
opencode-agent[bot] 756488d534 chore: generate 2026-05-14 16:42:18 +00:00
Shoubhit DashandGitHub 22de34c4de feat: add experimental background subagents (#27084) 2026-05-14 22:10:15 +05:30
Adam bdb0c16a93 chore: update web stats 2026-05-14 11:26:59 -05:00
7f7eb2e7f8 fix(provider): remove LiteLLM workarounds ported upstream, requires LiteLLM v1.85.0-rc.2+ (#26819)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 11:26:07 -05:00
opencode-agent[bot] e15fd0bb93 chore: generate 2026-05-14 13:33:44 +00:00
opencode-agent[bot] 8f90697df8 chore: generate 2026-05-14 13:32:19 +00:00
opencode-agent[bot] 17af25d1c1 chore: generate 2026-05-14 13:30:59 +00:00
Kit LangtonandGitHub 3c81326a5e docs(effect): refresh TODO with shipped P0 and RF work (#27536) 2026-05-14 09:29:32 -04:00
opencode-agent[bot] 9f8d8f5b0e chore: generate 2026-05-14 12:40:10 +00:00
OpeOginniandGitHub 337993d53e feat(desktop): add mcp client registration status and authentication handling (#27525) 2026-05-14 20:38:52 +08:00
Shoubhit DashandGitHub e26abd8da9 fix(tool): close shell truncation stream (#27517) 2026-05-14 16:34:42 +05:30
Shoubhit DashandGitHub 8c1ce0b80c refactor(flags): simplify tui plugin runtime flags (#27506) 2026-05-14 15:56:02 +05:30
Brendan AllanandGitHub f8c3f560d4 fix(desktop): await execFilePromise and read stdout properly (#27499) 2026-05-14 17:52:23 +08:00
Shoubhit DashandGitHub 7e43d3e3f5 refactor(lsp): type initialize errors (#27494) 2026-05-14 15:20:02 +05:30
opencode-agent[bot] 52db7a76e2 chore: update nix node_modules hashes 2026-05-14 09:28:30 +00:00
Shoubhit DashandGitHub be6e7b309e refactor(provider): type init errors (#27484) 2026-05-14 14:48:58 +05:30
Simon KleeandGitHub 0af242974c deps: Upgrade OpenTUI to 0.2.10 (#27491) 2026-05-14 09:14:03 +00:00
Shoubhit DashandGitHub 27ac53aaac fix(server): stop exposing named defects (#27471) 2026-05-14 12:51:05 +05:30
Shoubhit DashandGitHub 78015571bf refactor(server): centralize session busy mapping (#27473) 2026-05-14 12:50:36 +05:30
Aiden ClineandGitHub e76cf967e6 fix(session): finalize interrupted assistant messages (#27254) 2026-05-14 01:19:11 -05:00
opencode-agent[bot] c2723b5ea0 chore: generate 2026-05-14 04:25:32 +00:00
FrederikandGitHub 9675579796 fix: bug encountered when using azure gpt-5.5 w/ completions api (#26222) 2026-05-13 23:24:16 -05:00
opencode-agent[bot] 4d8368970a chore: update nix node_modules hashes 2026-05-14 04:20:42 +00:00
2a7af6acd8 fix(tui): preserve text selection on question prompt options (#24988)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2026-05-13 23:17:59 -05:00
opencode-agent[bot] bfd707abc9 chore: generate 2026-05-14 04:07:30 +00:00
Aiden ClineandGitHub 981e00971a fix: image resizer wasm loading, reenable image resizing (#26805) 2026-05-13 23:06:07 -05:00
Aiden ClineandGitHub c50d2b3656 Refactor event HTTP API route modules (#27441) 2026-05-13 22:41:17 -05:00
opencode ddad0988e7 sync release versions for v1.14.50 2026-05-14 03:03:23 +00:00
Kit LangtonandGitHub cda8cc7285 test(httpapi): simplify event stream regression coverage (#27427) 2026-05-14 02:18:40 +00:00
b928a1fff9 fix(httpapi): preserve event stream context (#27425)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: James Long <longster@gmail.com>
2026-05-13 22:02:30 -04:00
Kit LangtonandGitHub 04286d0415 docs(effect): plan Instance deletion path (#27424) 2026-05-13 21:58:54 -04:00
opencode-agent[bot] 33bb33ba90 chore: generate 2026-05-14 01:55:00 +00:00
SebastianandGitHub b0ade40265 flip back to markdown renderable (#27421) 2026-05-14 03:53:48 +02:00
Kit LangtonandGitHub 681594b551 refactor(storage): remove not found wire serializer (#27416) 2026-05-13 21:39:50 -04:00
Kit LangtonandGitHub edf7649400 fix(session): type busy errors (#27410) 2026-05-14 01:28:04 +00:00
Kit LangtonandGitHub 3fc7486d15 test(session): fix shell-cancel race when trap hasn't installed yet (#27408) 2026-05-14 01:10:40 +00:00
Kit LangtonandGitHub 8e353584c7 test(format): remove formatter check sleeps (#27407) 2026-05-13 21:02:34 -04:00
SebastianandGitHub 5c35ea2181 notification docs (#27406) 2026-05-14 03:01:25 +02:00
opencode-agent[bot] faf8713053 chore: generate 2026-05-14 00:59:33 +00:00
DaxandGitHub 16c457e712 refactor(core): move models.dev into core (#27347) 2026-05-13 20:58:24 -04:00
Kit LangtonandGitHub 9818c9e8d0 fix(provider): make small model fallback optional (#27405) 2026-05-14 00:44:34 +00:00
Kit LangtonandGitHub 5e41dbbcbf test(effect): use Effect sleep in instance state tests (#27404) 2026-05-13 20:43:46 -04:00
Kit LangtonandGitHub ba5c8d3822 fix(llm): preserve tool error defects (#27403) 2026-05-13 20:43:32 -04:00
opencode-agent[bot] 10c90eb445 chore: generate 2026-05-14 00:33:32 +00:00
Kit LangtonandGitHub aa8a41d1b8 effect(patch,tool): migrate patch/index and tool/read to AppFileSystem (#27155) 2026-05-13 20:32:19 -04:00
Kit LangtonandGitHub 3f33be1928 effect(server): typed errors in session/sync handlers, fix concurrency (#27146) 2026-05-13 20:31:27 -04:00
Kit LangtonandGitHub 42e6b7d541 effect(core): track stderr truncation; polish AppProcess callers (#27353) 2026-05-13 20:31:03 -04:00
Kit LangtonandGitHub ccb207f946 effect(util): migrate filesystem callers to AppFileSystem.Service (#27152) 2026-05-13 20:25:37 -04:00
Kit LangtonandGitHub de1e0b5d6d test(workspace): effectify sync state cases (#27400) 2026-05-13 19:49:03 -04:00
Aiden ClineandGitHub df3895d74f cleanup: make smallOptions rely on variants (#27390) 2026-05-13 18:30:36 -05:00
Kit LangtonandGitHub 55e0af1405 fix(provider): type model not found errors (#27334) 2026-05-13 22:23:09 +00:00
Kit LangtonandGitHub 5182a3698d test(workspace): use Effect for local session warp cases (#27393) 2026-05-13 22:22:51 +00:00
opencode 73e1de4513 sync release versions for v1.14.49 2026-05-13 22:18:40 +00:00
Frank 44b432c3fd sync 2026-05-13 18:05:06 -04:00
Kit LangtonandGitHub 0d8c9f3437 docs: add LayerMap example (#27388) 2026-05-13 17:46:47 -04:00
opencode-agent[bot] 0d074492df chore: update nix node_modules hashes 2026-05-13 21:20:10 +00:00
SebastianandGitHub 3b7a5e783d fix keymap fallback priority and TUI config diagnostics (#27384) 2026-05-13 23:00:48 +02:00
Frank c197fd92b7 sync 2026-05-13 15:58:34 -04:00
Shoubhit DashandGitHub 9ee1f6ceba fix(server): map busy sessions in http handlers (#27375) 2026-05-14 01:02:07 +05:30
Shoubhit DashandGitHub 20cec91550 fix(provider): restore model suggestions (#27372) 2026-05-14 00:38:38 +05:30
Aiden ClineandGitHub 22a5e6cc50 fix(run): restore non-interactive exit behavior (#27371) 2026-05-13 18:45:34 +00:00
Shoubhit DashandGitHub 52f9bcbb82 refactor(flags): route installation client through runtime flags (#27369) 2026-05-14 00:10:31 +05:30
Shoubhit DashandGitHub a4ebb07c25 refactor(flags): route llm client through runtime flags (#27368) 2026-05-14 00:09:53 +05:30
opencode-agent[bot] 7cc968b05d chore: generate 2026-05-13 16:47:21 +00:00
Frank fa077b92b1 zen: update sticky session logic 2026-05-13 12:45:11 -04:00
Kit LangtonandGitHub 8ad3a4b217 test(util): migrate log cleanup test to Effect (#27357) 2026-05-13 16:43:23 +00:00
Kit LangtonandGitHub 533495ae20 test(mcp): migrate OAuth auto-connect tests (#27356) 2026-05-13 16:38:37 +00:00
Kit LangtonandGitHub f0635e365f test(session): use Effect polling in processor tests (#27354) 2026-05-13 16:33:19 +00:00
Kit LangtonandGitHub 25de3e407b test(acp): use shared instance fixture for event tests (#27351) 2026-05-13 12:30:13 -04:00
Frank 655b25bccf sync 2026-05-13 12:05:30 -04:00
Kit LangtonandGitHub e5d13d9519 effect(git): migrate to AppProcess.run (#27190) 2026-05-13 12:04:51 -04:00
Kit LangtonandGitHub 5cdbb7505e effect(installation): migrate to AppProcess.run (#27188) 2026-05-13 11:54:29 -04:00
Kit LangtonandGitHub e5319846ad test(server): migrate pty websocket input test (#27348) 2026-05-13 15:43:09 +00:00
Kit LangtonandGitHub 832aa94977 effect(worktree): migrate to AppProcess.run (#27186) 2026-05-13 11:39:35 -04:00
Kit LangtonandGitHub 6c7f35b49e effect(format): migrate to AppProcess (#27185) 2026-05-13 15:26:42 +00:00
Kit LangtonandGitHub 6e25720307 test(tool): use Effect sleep in edit concurrency test (#27349) 2026-05-13 15:18:35 +00:00
Kit LangtonandGitHub ca723f1cbc effect(core): add stdin option to AppProcess.run; migrate snapshot+clipboard (#27224) 2026-05-13 11:10:23 -04:00
Kit LangtonandGitHub 650f67a05a chore: delete unused util/lock module (#27223) 2026-05-13 15:08:35 +00:00
opencode-agent[bot] 50dccac915 chore: generate 2026-05-13 15:06:14 +00:00
Kit LangtonandGitHub 02b8b0ff93 test: migrate file watcher test to Effect (#27346) 2026-05-13 15:04:30 +00:00
Kit LangtonandGitHub 76c91c6e33 test: migrate mcp oauth browser tests (#27345) 2026-05-13 15:04:02 +00:00
opencode-agent[bot] ca17ca85cd chore: update nix node_modules hashes 2026-05-13 15:02:16 +00:00
opencode-agent[bot] e7aed64949 chore: generate 2026-05-13 14:59:13 +00:00
Dax Raad d43124abe0 ignore: notes 2026-05-13 10:57:22 -04:00
Kit LangtonandGitHub 7404664827 refactor: migrate installation tests to testEffect (#27342) 2026-05-13 14:56:51 +00:00
Kit LangtonandGitHub 0b112e5bcf test: migrate permission task config tests (#27343) 2026-05-13 14:56:26 +00:00
Shoubhit DashandGitHub 268d758130 refactor(flags): route control-plane workspaces through runtime flags (#27337) 2026-05-13 20:22:30 +05:30
opencode-agent[bot] 72acdf0505 chore: generate 2026-05-13 14:50:34 +00:00
Shoubhit DashandGitHub e28ef7b57c refactor(flags): route sync workspaces through runtime flags (#27336) 2026-05-13 20:18:06 +05:30
opencode-agent[bot] 5b5376a3fa chore: generate 2026-05-13 14:47:40 +00:00
Kit LangtonandGitHub 766318a4cf effect(snapshot): migrate to AppProcess.run (#27189) 2026-05-13 10:46:14 -04:00
Kit LangtonandGitHub 8d5aa584b4 test(workspace): effectify sync start coverage (#27338) 2026-05-13 14:45:43 +00:00
Shoubhit DashandGitHub eed0eddc63 refactor(flags): route session workspaces through runtime flags (#27335) 2026-05-13 20:14:40 +05:30
DaxandGitHub 8345152319 core: expose v2 model listing API (#25821) 2026-05-13 14:43:08 +00:00
Kit LangtonandGitHub bebe5442a5 chore: delete unused util/color module (#27331) 2026-05-13 14:02:17 +00:00
Kit LangtonandGitHub bc25342f34 chore: delete util/scrap module (#27330) 2026-05-13 14:01:19 +00:00
Kit LangtonandGitHub 762020f63a chore: delete unused util/network module (#27329) 2026-05-13 13:56:15 +00:00
Shoubhit DashandGitHub f13fc5a8a8 refactor(flags): route event system through runtime flags (#27323) 2026-05-13 17:44:09 +05:30
Shoubhit DashandGitHub 098bdd8ae2 refactor(flags): route plan mode through runtime flags (#27320) 2026-05-13 17:17:04 +05:30
Shoubhit DashandGitHub 4d205027ca refactor(flags): route scout through runtime flags (#27318) 2026-05-13 17:07:53 +05:30
opencode-agent[bot] 5975547c84 chore: generate 2026-05-13 11:19:45 +00:00
Shoubhit DashandGitHub 5b2b300602 fix(session): tighten http error contracts (#27308) 2026-05-13 16:48:18 +05:30
opencode-agent[bot] d488e3fd2a chore: generate 2026-05-13 10:18:40 +00:00
Shoubhit DashandGitHub 809af5c590 fix(provider): type auth errors (#27301) 2026-05-13 15:47:13 +05:30
vimtor 733bd3c74e chore: activate low tps alerts 2026-05-13 12:12:03 +02:00
opencode-agent[bot] 374951bf60 chore: generate 2026-05-13 09:39:54 +00:00
Victor NavarroandGitHub 2e94f505a4 chore: add low tps model alerts (#27055) 2026-05-13 09:38:31 +00:00
opencode-agent[bot] 4498fc983d chore: generate 2026-05-13 09:36:51 +00:00
Shoubhit DashandGitHub 2e7cf92c8b fix(worktree): type expected errors (#27296) 2026-05-13 15:05:30 +05:30
Shoubhit DashandGitHub ccf93f3523 fix(session): make message reads effectful (#27291) 2026-05-13 14:40:12 +05:30
Shoubhit DashandGitHub 4b041716fc fix(server): remove storage not found defect fallback (#27287) 2026-05-13 14:15:53 +05:30
Shoubhit DashandGitHub b0dc8e4638 fix(session): use typed message reads in tools (#27280) 2026-05-13 14:12:51 +05:30
OpeOginniandGitHub 596f241db5 fix(app): enhance error handling by unwrapping SDK-wrapped errors in formatServerError (#27061) 2026-05-13 13:53:10 +05:30
Luke ParkerandGitHub 3a810fcb9a perf(ui): render icons through an svg sprite (#26950) 2026-05-13 17:57:13 +10:00
opencode-agent[bot] e5af7ab99a chore: generate 2026-05-13 07:53:28 +00:00
Shoubhit DashandGitHub f01c6b3e37 fix(session): type message list not found errors (#27275) 2026-05-13 13:22:12 +05:30
Shoubhit DashandGitHub fed043a1ad fix(session): add typed message lookup wrappers (#27269) 2026-05-13 13:04:07 +05:30
Shoubhit DashandGitHub e9a29e4908 fix(storage): type not found errors (#27265) 2026-05-13 12:25:04 +05:30
Brendan AllanandGitHub d93a06431e refactor(app): clarify session_working logic in child-store (#27267) 2026-05-13 14:36:00 +08:00
opencode-agent[bot] 9fe912439b chore: generate 2026-05-13 05:41:29 +00:00
Shoubhit DashandGitHub dd46fddf22 test(cli): cover config json diagnostics (#27257) 2026-05-13 05:40:12 +00:00
opencode-agent[bot] d3d7b44e73 chore: generate 2026-05-13 05:32:32 +00:00
Shoubhit DashandGitHub 367665dba2 fix(cli): render tagged config errors (#27256) 2026-05-13 11:01:18 +05:30
Brendan AllanandGitHub 4aaece29d9 feat(desktop): reintroduce AppStream MetaInfo for Linux desktop builds (#27253) 2026-05-13 13:14:39 +08:00
opencode-agent[bot] bed88ce50e chore: generate 2026-05-13 04:56:52 +00:00
Aiden ClineandGitHub 28204720dc temporarily revert: preserve permission ordering by accepting a layered array (#27258) 2026-05-12 23:55:45 -05:00
Brendan AllanandGitHub 10b99b2f5a build(ci): use native arm64 runner for desktop linux arm64 builds (#27250) 2026-05-13 12:52:18 +08:00
Shoubhit DashandGitHub 90c13d93f3 fix(server): hide unknown 500 details (#27251) 2026-05-13 10:15:28 +05:30
Aiden ClineandGitHub 67e6408cef fix: disable image module for now (#27248) 2026-05-12 23:21:31 -05:00
Brendan AllanandGitHub 3be65dff46 fix: add optional chaining to session_status access (#27247) 2026-05-13 12:09:36 +08:00
opencode-agent[bot] c5961205ef chore: update nix node_modules hashes 2026-05-13 03:44:43 +00:00
Brendan AllanandGitHub ad6a8a1850 fix: use htmlrewriter2 instead of HTMLRewriter for node compat (#26309) 2026-05-13 03:28:08 +00:00
Kit LangtonandGitHub 46daede10c test(pty): migrate output isolation to Effect runner (#27235) 2026-05-13 03:25:52 +00:00
Kit LangtonandGitHub 8249baeb4e test(pty): migrate shell tests to Effect runner (#27238) 2026-05-13 03:20:20 +00:00
Frank 77e51b0a32 zen: stat worker 2026-05-12 23:19:25 -04:00
opencode-agent[bot] 784796e27a chore: generate 2026-05-13 03:14:19 +00:00
Kit LangtonandGitHub 913ea36ae6 test(server): scope MCP HttpApi handler (#27226) 2026-05-13 03:13:05 +00:00
Kit LangtonandGitHub 68c4951318 test(mcp): migrate lifecycle tests to Effect runner (#27205) 2026-05-13 03:05:30 +00:00
Kit LangtonandGitHub 6d3b2fe08b test(server): stabilize SDK project skill prompt test (#27239) 2026-05-13 03:01:29 +00:00
Kit LangtonandGitHub d88cef6ada test(mcp): migrate headers tests to Effect runner (#27237) 2026-05-13 02:56:29 +00:00
Kit LangtonandGitHub 8370d0cef4 test(server): migrate httpapi ui tests to effect runner (#27236) 2026-05-13 02:55:36 +00:00
Kit LangtonandGitHub 0b67e1a046 test(server): migrate session messages to Effect runner (#27234) 2026-05-13 02:55:33 +00:00
Kit LangtonandGitHub 485ecbde18 test(server): migrate global session list to effect runner (#27233) 2026-05-13 02:52:59 +00:00
Kit LangtonandGitHub 03cf833236 test(provider): migrate DigitalOcean provider test to Effect runner (#27232) 2026-05-13 02:51:11 +00:00
Kit LangtonandGitHub e3684f36f9 chore: delete unused util/abort module + orphaned leak test (#27230) 2026-05-13 02:46:41 +00:00
Kit LangtonandGitHub 13fbc9acfc docs(effect): add cleanup roadmap (#27228) 2026-05-13 02:45:26 +00:00
Kit LangtonandGitHub 588b5240d0 test(server): migrate worktree endpoint repro to effect runner (#27220) 2026-05-13 02:43:41 +00:00
80543fb5dc fix(desktop): resolve login shell when loading env (#26449)
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
2026-05-13 10:40:36 +08:00
Kit LangtonandGitHub ff16eb8dea test(project): use Deferred for dispose handoff (#27225) 2026-05-13 02:32:50 +00:00
Kit LangtonandGitHub 91a9514ed0 test(server): use AppFileSystem in provider tests (#27227) 2026-05-13 02:32:30 +00:00
Brendan AllanandGitHub 2f4dce789f app: use session_working helper to simplify loading states (#27212) 2026-05-13 10:27:05 +08:00
opencode-agent[bot] b43147440c chore: generate 2026-05-13 02:16:48 +00:00
Kit LangtonandGitHub c96a77c60b test(pty): migrate session tests to Effect runner (#27222) 2026-05-13 02:15:38 +00:00
opencode-agent[bot] 6cd2a743b5 chore: generate 2026-05-13 02:10:48 +00:00
Luke ParkerandGitHub 0f8517208b perf(app): unmount closed review panel (#27221) 2026-05-13 12:09:34 +10:00
Kit LangtonandGitHub 0879f5e22d test(server): migrate project init git test to Effect runner (#27218) 2026-05-13 02:08:55 +00:00
opencode-agent[bot] 16333b5222 chore: generate 2026-05-13 02:08:16 +00:00
Kit LangtonandGitHub e16f4b6b99 test(permission): migrate next tests to effect runner (#27217) 2026-05-13 02:06:58 +00:00
Kit LangtonandGitHub 6fbb08b724 test(project): migrate instance tests to effect runner (#27215) 2026-05-13 02:06:16 +00:00
Kit LangtonandGitHub a26a2a95bd test(server): migrate provider httpapi test to effect runner (#27216) 2026-05-13 02:05:52 +00:00
Kit LangtonandGitHub 7f9268f147 test(server): migrate global bus helper to Effect (#27214) 2026-05-13 02:04:46 +00:00
Kit LangtonandGitHub 5c7af682b9 test(server): migrate MCP HTTP API test to Effect runner (#27213) 2026-05-13 02:03:52 +00:00
Kit LangtonandGitHub 911b2ac088 test(session): migrate prompt tests to effect runner (#27209) 2026-05-13 01:51:35 +00:00
Kit LangtonandGitHub da689d77c4 effect: move tool flags into RuntimeFlags (#27198) 2026-05-12 21:45:53 -04:00
opencode-agent[bot] c9df833d2c chore: generate 2026-05-13 01:45:20 +00:00
Aiden ClineandGitHub c2b1ebd9dc feat: update pricing schema for models to ensure more accurate cost tracking (#27184) 2026-05-12 20:44:06 -05:00
Kit LangtonandGitHub d1356f509e test(server): migrate HTTP API SDK test to Effect runner (#27208) 2026-05-13 01:43:35 +00:00
opencode-agent[bot] 69feb224ba chore: update nix node_modules hashes 2026-05-13 01:43:08 +00:00
Kit LangtonandGitHub 7d9ac713a9 test(config): migrate TUI config tests to Effect runner (#27206) 2026-05-13 01:42:33 +00:00
Kit LangtonandGitHub 4d9c675b00 test(server): migrate httpapi session test to effect runner (#27207) 2026-05-13 01:40:25 +00:00
Kit LangtonandGitHub 604de70689 test(server): migrate experimental HttpApi test to Effect (#27204) 2026-05-13 01:40:07 +00:00
opencode-agent[bot] 673226d214 chore: generate 2026-05-13 01:39:46 +00:00
Kit LangtonandGitHub 2447f42294 test(server): migrate session select to effect runner (#27203) 2026-05-13 01:38:38 +00:00
Frank 005e64e7d8 zen: stat worker 2026-05-12 21:37:41 -04:00
Kit LangtonandGitHub 8310e7df70 test(server): migrate missing patch diff test (#27202) 2026-05-13 01:37:34 +00:00
Kit LangtonandGitHub c4e676b8a0 fix(task): preserve subagent self permissions (#27201) 2026-05-13 01:36:02 +00:00
opencode-agent[bot] c2c40b5b61 chore: generate 2026-05-13 01:28:35 +00:00
Kit LangtonandGitHub 456495289e fix(httpapi): drop redundant InstanceRef/WorkspaceRef in session prompt handler (#27196) 2026-05-13 01:27:08 +00:00
SebastianandGitHub d6367853ae Add TUI notifications and attention sounds (disabled by default) (#26980) 2026-05-13 03:26:25 +02:00
opencode-agent[bot] adccab5970 chore: generate 2026-05-13 01:26:12 +00:00
Kit LangtonandGitHub b6d3fa09bc effect(core): add AppProcess service (Phase 1) (#27178) 2026-05-13 01:24:53 +00:00
Kit LangtonandGitHub 31e2d72bf7 test(worktree): scope created worktree cleanup (#27191) 2026-05-12 21:09:58 -04:00
Kit LangtonandGitHub b7c6fa611f effect: add RuntimeFlags service (#27181) 2026-05-12 20:59:02 -04:00
opencode-agent[bot] d0b8ff0f22 chore: update nix node_modules hashes 2026-05-13 00:57:32 +00:00
Kit LangtonandGitHub 59b976b954 Remove TUI logo sound effects (#27183) 2026-05-12 20:37:16 -04:00
Luke ParkerandGitHub d1640c075b fix(app): use session status for busy state (#27166) 2026-05-13 10:25:28 +10:00
Kit LangtonandGitHub 17d4c366e6 test(worktree): dispose created instances before removal (#27182) 2026-05-12 20:23:20 -04:00
Kit LangtonandGitHub d0844c600b test(worktree): use timeoutOrElse for ready wait (#27180) 2026-05-12 20:14:05 -04:00
Dax Raad 1d243ce25a harden cache usage 2026-05-12 20:06:46 -04:00
Kit LangtonandGitHub d8c8322ddf test: migrate worktree tests to effect runner (#27177) 2026-05-12 19:55:07 -04:00
Kit LangtonandGitHub 1b6599f411 test(plugin): use noop dependency boundaries (#27148) 2026-05-12 19:53:46 -04:00
opencode-agent[bot] 937a3c10b3 chore: generate 2026-05-12 23:49:28 +00:00
Kit LangtonandGitHub 72ce24c200 test: migrate effect cmd ALS test (#27173) 2026-05-12 23:48:17 +00:00
Kit LangtonandGitHub 3301fad8cd test: migrate app runtime logger effect tests (#27176) 2026-05-12 23:47:49 +00:00
Kit LangtonandGitHub 9c54255aeb fix: migrate sync http api test to effect runner (#27175) 2026-05-12 23:47:14 +00:00
Kit LangtonandGitHub b0674b473f test: migrate session action route to effect runner (#27174) 2026-05-12 23:46:51 +00:00
Kit LangtonandGitHub ded4da735b test: migrate webfetch tool tests to effect runner (#27171) 2026-05-12 23:46:23 +00:00
Kit LangtonandGitHub 2c334d9242 Migrate schema error body tests to Effect runner (#27172) 2026-05-12 23:46:19 +00:00
Kit LangtonandGitHub 81dd46abec test: migrate websearch tests to effect runner (#27170) 2026-05-12 23:45:01 +00:00
opencode-agent[bot] baef5cd43b chore: generate 2026-05-12 22:11:13 +00:00
65368f609d fix: preserve permission ordering by accepting a layered array (#23214)
Co-authored-by: Andrew Suffield <asuffield@cloudflare.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2026-05-12 17:09:06 -05:00
opencode-agent[bot] 2cb697b720 chore: generate 2026-05-12 21:24:39 +00:00
Aiden ClineandGitHub cb511f78ff fix(plugin): preserve tool attachments (#27157) 2026-05-12 16:23:15 -05:00
MusaandGitHub 159964b172 feat(plugin): add DigitalOcean OAuth + Inference Routers (#26095) 2026-05-12 16:22:40 -05:00
Kit LangtonandGitHub d9f9f1553b test: use Effect file services in migrated tests (#27154) 2026-05-12 20:48:07 +00:00
Kit LangtonandGitHub 0fb55b4f1a test(project): migrate global project tests to Effect runner (#27142) 2026-05-12 20:45:39 +00:00
Kit LangtonandGitHub 3c34f6704b test: migrate auth override plugin test (#27140) 2026-05-12 20:41:34 +00:00
Kit LangtonandGitHub 4cf088ae84 test: migrate instance bootstrap to Effect runner (#27144) 2026-05-12 20:34:12 +00:00
Aiden ClineandGitHub ca28dd02ec fix(compaction): restore tail turns after summarization (#27145) 2026-05-12 15:33:16 -05:00
Kit LangtonandGitHub 2017dc165c test: migrate negative tokens regression to Effect runner (#27141) 2026-05-12 20:32:23 +00:00
Kit LangtonandGitHub dc9d6a08cb test: migrate agent color config tests (#27139) 2026-05-12 20:31:38 +00:00
Kit LangtonandGitHub af4ab017cb test(session): migrate structured output integration test (#27143) 2026-05-12 20:30:35 +00:00
Kit LangtonandGitHub dd14413a64 Preserve native LLM tool context (#27116) 2026-05-12 16:16:58 -04:00
Frank b9e7cbf13c sync 2026-05-12 16:06:19 -04:00
Kit LangtonandGitHub 3f74abc6cd test: simplify Effect migration follow-ups (#27136) 2026-05-12 20:00:54 +00:00
Kit LangtonandGitHub e0d0fe1ff7 test(bus): migrate integration tests to Effect runner (#27132) 2026-05-12 19:58:54 +00:00
opencode-agent[bot] f7dbb4dac4 chore: generate 2026-05-12 19:48:35 +00:00
Kit LangtonandGitHub c5849e56cc test(project): migrate project tests to Effect runner (#27134) 2026-05-12 19:47:17 +00:00
opencode-agent[bot] e46ab34d27 chore: generate 2026-05-12 19:44:26 +00:00
Kit LangtonandGitHub 1d4613006a test(project): migrate instance tests to Effect runner (#27130) 2026-05-12 19:41:46 +00:00
Kit LangtonandGitHub 71040c54aa test(plugin): migrate loader shared tests to Effect runner (#27129) 2026-05-12 19:41:44 +00:00
Kit LangtonandGitHub fec78154b5 test(bus): migrate bus tests to Effect runner (#27131) 2026-05-12 19:41:24 +00:00
Kit LangtonandGitHub 3e2ec192cf test(question): remove WithInstance bridge (#27128) 2026-05-12 19:40:01 +00:00
Kit LangtonandGitHub ec960da42a test(skill): migrate discovery tests to Effect runner (#27127) 2026-05-12 19:39:03 +00:00
Shoubhit DashandGitHub 45de4975de refactor(core): resolve default agent info (#27125) 2026-05-13 01:08:30 +05:30
Kit LangtonandGitHub e540daabc4 test(agent): migrate plan bypass tests to Effect runner (#27119) 2026-05-12 14:56:01 -04:00
opencode-agent[bot] f3c91c5f96 chore: generate 2026-05-12 18:52:25 +00:00
Kit LangtonandGitHub 549b146ea6 Stabilize session event tests (#27117) 2026-05-12 18:51:18 +00:00
Kit LangtonandGitHub 3c7569d852 test(tool): migrate external directory tests to Effect runner (#27122) 2026-05-12 18:50:56 +00:00
Kit LangtonandGitHub 8f1ded9e08 test(file): migrate ripgrep tests to Effect runner (#27120) 2026-05-12 18:50:26 +00:00
Kit LangtonandGitHub b668af29dd test(git): migrate git tests to Effect runner (#27121) 2026-05-12 18:50:07 +00:00
Kit LangtonandGitHub ec30ff9120 test(agent): migrate agent tests to Effect runner (#27118) 2026-05-12 18:49:30 +00:00
opencode-agent[bot] a3714d4399 chore: update nix node_modules hashes 2026-05-12 18:27:42 +00:00
Kit LangtonandGitHub 822eec0d62 Fix runner cancel completion (#27115) 2026-05-12 14:22:56 -04:00
Kit LangtonandGitHub 3974520742 Migrate UI cancel error to tagged error (#27112) 2026-05-12 18:09:00 +00:00
Kit LangtonandGitHub fda37b3609 Remove Zod from app global SDK (#27111) 2026-05-12 14:02:12 -04:00
Kit LangtonandGitHub 6b950b666a Remove Zod from core dependencies (#27107) 2026-05-12 13:51:08 -04:00
Kit LangtonandGitHub bc4fdb8370 Remove unused app ID schema (#27105) 2026-05-12 13:09:23 -04:00
Kit LangtonandGitHub 2b9af91568 Remove Zod from core log (#27102) 2026-05-12 13:08:57 -04:00
Kit LangtonandGitHub 53a3f95088 Make core fn Zod import type-only (#27103) 2026-05-12 12:58:50 -04:00
Dax Raad 5a4596c879 core: Wait 3 days before installing new package versions to reduce supply chain risk 2026-05-12 12:50:32 -04:00
opencode-agent[bot] 0ce614a280 chore: generate 2026-05-12 16:46:35 +00:00
Kit LangtonandGitHub e8125e9b42 test(server): migrate session list tests to Effect runner (#27101) 2026-05-12 16:45:05 +00:00
Kit LangtonandGitHub a7b5041674 test(file): migrate fsmonitor tests to Effect runner (#27099) 2026-05-12 16:44:04 +00:00
Kit LangtonandGitHub a16789dfdd test(tool): migrate apply patch tests to Effect runner (#27100) 2026-05-12 16:43:33 +00:00
Kit LangtonandGitHub 8115004c73 test(file): migrate path traversal tests to Effect runner (#27098) 2026-05-12 16:42:49 +00:00
Kit LangtonandGitHub ec4fdaf8e9 test(tool): migrate tool define tests to Effect runner (#27097) 2026-05-12 16:42:19 +00:00
Shoubhit DashandGitHub 3dc2c1d81c fix(session): preserve usage update timestamps (#27094) 2026-05-12 22:10:28 +05:30
Kit LangtonandGitHub d658e1e350 Remove local MCP Zod schema (#27095) 2026-05-12 12:38:27 -04:00
opencode-agent[bot] 30e3fa1de9 chore: generate 2026-05-12 16:33:06 +00:00
Aiden ClineandGitHub 23f8b3eb3e fix: annotate Effect log metadata (#27093) 2026-05-12 11:31:18 -05:00
Kit LangtonandGitHub c7d8b0d565 Delete named schema error wrapper (#27066) 2026-05-12 12:04:28 -04:00
Kit LangtonandGitHub 257fcafc83 test(tool): migrate edit concurrency test (#26983) 2026-05-12 11:52:31 -04:00
Kit LangtonandGitHub 04aafe2bfc test(provider): migrate more config-backed cases (#27067) 2026-05-12 14:19:49 +00:00
opencode-agent[bot] 0fd0facc44 chore: generate 2026-05-12 13:31:03 +00:00
Kit LangtonandGitHub 0de3b67cc0 test(tool): migrate shell tests to Effect runner (#26968) 2026-05-12 13:28:46 +00:00
Kit LangtonandGitHub 28f38fc871 Remove Zod from named errors (#26982) 2026-05-12 09:20:15 -04:00
Shoubhit DashandGitHub 8feb4a31c7 feat(core): add background job service (#27033) 2026-05-12 15:22:38 +05:30
Simon KleeandGitHub 8f05bbfaa6 prompt: fix cursor math for wide characters (#27017)
String.length counts code points, not display columns, so CJK
characters and emoji that occupy two terminal cells caused
misaligned cursors, broken mention triggers, and incorrect
history restoration offsets.

Use Bun.stringWidth for now, we need an alternative for this.

Fix #26716
Close #26922
2026-05-12 11:45:28 +02:00
Brendan AllanandGitHub d276d96cdf fix(app): remember selected model variant when switching sessions/projects (#27029) 2026-05-12 17:44:50 +08:00
caf1151cb5 refactor(app): centralize sync query options (#25941)
Co-authored-by: Brendan Allan <git@brendonovich.dev>
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
2026-05-12 16:40:21 +08:00
Brendan AllanandGitHub ff38bbeeeb refactor(desktop): remove configureEnv callback from spawnLocalServer (#27022) 2026-05-12 16:39:56 +08:00
Shoubhit DashandGitHub 2481dde36d chore: remove codesearch tool (#27019) 2026-05-12 13:44:02 +05:30
Matt HandGitHub 61174b7878 fix(tui): make websearch provider label reactive (#26943) 2026-05-12 08:01:16 +00:00
opencode-agent[bot] 907281a80a chore: generate 2026-05-12 06:44:09 +00:00
Brendan AllanandGitHub 3992e2a76b feat(app): add ctrl/cmd+number keybinds to switch projects (#26280) 2026-05-12 14:43:07 +08:00
opencode-agent[bot] ea6eabe1d9 chore: generate 2026-05-12 05:20:22 +00:00
DaxandGitHub 36d40fee4d Track session usage totals (#26644) 2026-05-12 01:18:57 -04:00
James LongandGitHub e36bc20f84 fix(tui): fix flicker by avoiding redundant workspace session sync (#26997) 2026-05-12 00:30:03 -04:00
Aiden ClineandGitHub 487575773d feat: create global opencode.jsonc if no configs exist (#26992) 2026-05-11 23:13:22 -05:00
opencode-agent[bot] 5cc84800dc chore: generate 2026-05-12 03:43:40 +00:00
James LongandGitHub 2b432d9e03 fix(tui): scope events by project (#26936) 2026-05-11 23:42:04 -04:00
opencode-agent[bot] 591eb667d5 chore: generate 2026-05-12 03:26:47 +00:00
Aiden ClineandGitHub ddce776225 ignore: add codebase skill to repo (#26990) 2026-05-12 03:25:41 +00:00
Aiden ClineandGitHub 1a28924ed8 fix: grep external directory permission evaluation (#26958) 2026-05-11 21:47:35 -05:00
Brendan AllanandGitHub 871374804f fix(app): use keyed Show for project in layout (#26985) 2026-05-12 10:39:36 +08:00
Brendan AllanandGitHub 78a2639e5e fix(app): open next project when closing current one (#26987) 2026-05-12 10:38:21 +08:00
Kit LangtonandGitHub cc1835e0db test(provider): migrate config-backed cases to Effect runner (#26969) 2026-05-12 02:23:52 +00:00
Kit LangtonandGitHub 0f5d4ae648 test(project): stabilize VCS branch update test (#26979) 2026-05-11 22:12:07 -04:00
Kit LangtonandGitHub ce72020750 test(tool): migrate edit tests to Effect runner (#26977) 2026-05-11 21:42:17 -04:00
Kit LangtonandGitHub c43d606f8e agent: use Effect schema for generated agent object (#26973) 2026-05-11 21:42:04 -04:00
Kit LangtonandGitHub 1007630347 Migrate runtime validators to Effect Schema (#26975) 2026-05-11 21:41:56 -04:00
Kit LangtonandGitHub 9e8274d2da Remove internal Zod schemas (#26974) 2026-05-11 21:40:44 -04:00
Kit LangtonandGitHub 74aa735e6a fix(tui): guard prompt submit against concurrent invocation (#26972) 2026-05-12 01:35:28 +00:00
Kit LangtonandGitHub 8030a6c187 Emit LLM stream lifecycle events (#26971) 2026-05-11 21:31:48 -04:00
Kit LangtonandGitHub e5aa5161f2 Remove effect-zod bridge (#26956) 2026-05-11 21:14:55 -04:00
Kit LangtonandGitHub abb1ee6278 docs(test): add Effect migration orchestration notes (#26963) 2026-05-11 20:59:51 -04:00
Kit LangtonandGitHub c4003579bb test(project): migrate VCS tests to Effect runner (#26965) 2026-05-11 20:59:34 -04:00
Kit LangtonandGitHub 0d9c534184 test(snapshot): migrate snapshot tests to Effect runner (#26964) 2026-05-11 20:59:31 -04:00
Aiden ClineandGitHub 5773d43cbf ci: GitHub Actions dependencies (#26962) 2026-05-11 19:50:35 -05:00
opencode-agent[bot] e0e9414cbd chore: generate 2026-05-12 00:41:30 +00:00
Kit LangtonandGitHub 44edb639c2 test(session): migrate message pagination to Effect runner (#26957) 2026-05-12 00:40:23 +00:00
Kit LangtonandGitHub fbd52ca2f4 test(file): migrate file tests to Effect runner (#26959) 2026-05-12 00:39:31 +00:00
opencode-agent[bot] 8015ff7ca5 chore: generate 2026-05-12 00:33:34 +00:00
Kit LangtonandGitHub ec9584177f docs(test): plan Effect test migration (#26954) 2026-05-11 20:32:27 -04:00
Kit LangtonandGitHub 061efc6cf2 Fix run JSON output draining (#26955) 2026-05-11 20:30:23 -04:00
Brendan AllanandGitHub fe374aea46 feat(app): persist todo dock collapsed state (#26953) 2026-05-11 23:59:38 +00:00
Kit LangtonandGitHub 46edc98f10 Validate TUI config with Effect Schema (#26952) 2026-05-11 23:51:45 +00:00
Kit LangtonandGitHub fdeb2748e1 test(agent): isolate plugin agent regression (#26948) 2026-05-11 19:38:54 -04:00
Kit LangtonandGitHub 59e6967b8f Generate config schema from Effect Schema (#26939) 2026-05-11 19:24:58 -04:00
opencode-agent[bot] 0c619cb59c chore: generate 2026-05-11 22:34:04 +00:00
Frank 0cf90109dc zen: tps rate limit 2026-05-11 18:32:39 -04:00
Kit LangtonandGitHub 812668ae2f Generate TUI schema from Effect Schema (#26945) 2026-05-11 17:50:14 -04:00
Kit LangtonandGitHub a5c35bf182 Avoid bootstrapping server plugins from TUI plugin runtime (#26938) 2026-05-11 17:32:16 -04:00
opencode-agent[bot] bdd5a80886 chore: update nix node_modules hashes 2026-05-11 21:28:49 +00:00
Kit LangtonandGitHub fd65d29dcc Drop unused opencode Zod statics (#26935) 2026-05-11 17:14:18 -04:00
Kit LangtonandGitHub d3caac5270 chore(deps): upgrade effect to 4.0.0-beta.65 (#26934) 2026-05-11 21:09:57 +00:00
Kit LangtonandGitHub fe7ca3421e Drop Config Info Zod static (#26933) 2026-05-11 16:49:22 -04:00
Kit LangtonandGitHub cc95197d72 Drop prompt input Zod statics (#26923) 2026-05-11 16:49:08 -04:00
James LongandGitHub 9067218b74 fix(core): always start worktrees as detached (#26931) 2026-05-11 16:22:25 -04:00
Kit LangtonandGitHub 42a0453945 Drop small session Zod statics (#26921) 2026-05-11 16:12:31 -04:00
Kit LangtonandGitHub 4d9eb6c320 Validate structured output tests with Effect Schema (#26919) 2026-05-11 16:11:25 -04:00
Kit LangtonandGitHub c060c436b6 Drop LSP config Zod statics (#26920) 2026-05-11 16:11:11 -04:00
Kit LangtonandGitHub 45adfedd64 Drop unused domain Zod statics (#26927) 2026-05-11 16:10:58 -04:00
opencode-agent[bot] 0bced8ec96 chore: update nix node_modules hashes 2026-05-11 17:32:56 +00:00
Kit LangtonandGitHub 8d9b9719be Drop unused small ID Zod statics (#26908) 2026-05-11 13:22:59 -04:00
Kit LangtonandGitHub c7e084c32c Simplify single-backend HttpApi exerciser (#26906) 2026-05-11 13:22:31 -04:00
Kit LangtonandGitHub 6f2f759fbb Clean up post-Hono references (#26903) 2026-05-11 13:20:54 -04:00
opencode-agent[bot] cddab63808 chore: generate 2026-05-11 17:17:38 +00:00
Shoubhit DashandGitHub 12583b18f0 feat(tui): pin, quick-switch, and cycle recent sessions (#26858) 2026-05-11 22:46:27 +05:30
Kit LangtonandGitHub df386bd651 feat(skill): enable customize-opencode by default, link full schema (#26899) 2026-05-11 13:13:41 -04:00
opencode-agent[bot] 25b12ed754 chore: generate 2026-05-11 17:06:57 +00:00
Kit LangtonandGitHub 023e1c711e refactor(llm): colocate per-type factories on their namespaces (#26799) 2026-05-11 13:05:41 -04:00
Kit LangtonandGitHub 52f7ba7d4d fix(llm): drop removed dispatch option from recorded cache tests (#26900) 2026-05-11 11:48:30 -04:00
opencode-agent[bot] 19fce2bc6f chore: generate 2026-05-11 15:21:20 +00:00
Shoubhit DashandGitHub 4bae84c8b0 feat(scout): autocomplete configured mentions (#26843) 2026-05-11 20:50:03 +05:30
Kit LangtonandGitHub f240bba8e7 chore(http-recorder): remove content-matching dispatch mode (#26792) 2026-05-11 11:10:18 -04:00
Kit LangtonandGitHub bcee247988 Define project update input with Effect Schema (#26803) 2026-05-11 15:05:31 +00:00
Kit LangtonandGitHub 64c504212a Parse command config with Effect Schema (#26801) 2026-05-11 10:22:45 -04:00
opencode-agent[bot] 6592d80460 chore: generate 2026-05-11 14:13:39 +00:00
SebastianandGitHub d821650b48 add default diff parser for markdown fenced code blocks (#26887) 2026-05-11 14:12:32 +00:00
Victor NavarroandGitHub 6c9f12bb2d chore: exclude status 429 from free model alerts (#26879) 2026-05-11 16:04:54 +02:00
opencode-agent[bot] fca89e5e4d chore: generate 2026-05-11 13:44:39 +00:00
Frank 1eff01b6a5 sync 2026-05-11 09:43:12 -04:00
opencode-agent[bot] e93b1f3a7f chore: generate 2026-05-11 13:38:44 +00:00
Frank 8874d4a42f zen: deekseek v4 flash free 2026-05-11 09:37:14 -04:00
Brendan AllanandGitHub c933504d9c fix(ui): better handle patch file support when rendering patch/edit tools (#26828) 2026-05-11 17:21:59 +08:00
Shoubhit DashandGitHub 2d0d3d596e feat(compaction): serialize compaction tail (#26830) 2026-05-11 13:40:36 +05:30
opencode-agent[bot] 3bd98ea055 chore: generate 2026-05-11 07:28:32 +00:00
Shoubhit DashandGitHub 7e997cfba4 refactor(scout): resolve configured reference mentions (#26701) 2026-05-11 12:57:26 +05:30
Brendan AllanandGitHub 5d6f2a1524 fix(ui): use part_text_accum_delta to prevent markdown cutoff during streaming (#26822) 2026-05-11 15:15:03 +08:00
opencode-agent[bot] b1cb71856e chore: generate 2026-05-11 05:27:40 +00:00
Aiden ClineandGitHub 518264fcd9 fix(opencode): fix full session fork (#26811) 2026-05-11 00:26:36 -05:00
DaxandGitHub 7235c9c9b8 Trace data migrations (#26809) 2026-05-11 03:23:01 +00:00
Kit LangtonandGitHub 274033cd52 Validate prompt messages with Effect Schema (#26796) 2026-05-11 02:59:20 +00:00
Kit LangtonandGitHub 9b369ee815 chore(llm): make cache: 'auto' the default (#26798) 2026-05-10 22:46:01 -04:00
SebastianandGitHub 721ff5121e fix prompt history behaviour and session line up/down commands (#26797) 2026-05-11 02:27:46 +00:00
opencode-agent[bot] cfbf5d1c6f chore: update nix node_modules hashes 2026-05-11 02:20:35 +00:00
opencode-agent[bot] 02cb7e7b71 chore: generate 2026-05-11 02:11:07 +00:00
Kit LangtonandGitHub 942630eb4a feat(llm): cache-policy auto-placement (#26786) 2026-05-10 22:09:55 -04:00
opencode ce66b191d1 sync release versions for v1.14.48 2026-05-11 02:07:48 +00:00
Kit LangtonandGitHub 6f1f5944ce Delete unused opencode Zod helpers (#26793) 2026-05-10 21:57:18 -04:00
opencode-agent[bot] 1c49b2ed67 chore: generate 2026-05-11 01:55:22 +00:00
opencode-agent[bot] 3c6be604ec chore: update nix node_modules hashes 2026-05-11 01:54:13 +00:00
Kit LangtonandGitHub ddc02c2893 Drop synchronous SyncEvent facades (#26789) 2026-05-11 01:53:50 +00:00
Kit LangtonandGitHub 2703eff2e2 refactor(llm): normalize Usage as inclusive total + non-overlapping breakdown (#26735) 2026-05-10 21:52:50 -04:00
opencode-agent[bot] 38e4540119 chore: generate 2026-05-11 01:41:26 +00:00
Dax Raad 4100fcbd17 disable image resizing 2026-05-10 21:40:12 -04:00
Kit LangtonandGitHub 83cb0f60ec Drop EventV2 run facade (#26783) 2026-05-10 21:26:28 -04:00
Kit LangtonandGitHub effd96755e Use SyncEvent service at event call sites (#26782) 2026-05-10 21:20:13 -04:00
opencode-agent[bot] 5801cce1b5 chore: generate 2026-05-11 01:18:39 +00:00
Kit LangtonandGitHub 77e6c0d329 feat(llm): cache hint TTL, breakpoint cap, and tool placement (#26779) 2026-05-10 21:17:38 -04:00
Kit LangtonandGitHub fed716ada5 Clarify compaction test harness (#26777) 2026-05-10 20:41:21 -04:00
opencode 426d92e352 sync release versions for v1.14.47 2026-05-11 00:23:17 +00:00
opencode-agent[bot] d0412a213b chore: generate 2026-05-11 00:18:03 +00:00
Kit LangtonandGitHub 16aa67086b Effectify remaining compaction process tests (#26776) 2026-05-10 20:17:01 -04:00
DaxandGitHub 7cea32ee08 Add background code migration service (#26652) 2026-05-11 00:16:42 +00:00
Kit LangtonandGitHub 128d10d9e9 Simplify compaction test helpers (#26742) 2026-05-10 20:03:11 -04:00
Kit LangtonandGitHub 5ef72e1101 Drop unused ID Zod statics (#26740) 2026-05-10 19:58:21 -04:00
Kit LangtonandGitHub d8060dc9ad Drop compaction create facade (#26739) 2026-05-10 19:54:16 -04:00
Kit LangtonandGitHub f71fb18d3d Replace compaction create test fixtures (#26738) 2026-05-10 19:53:22 -04:00
SebastianandGitHub 5654dd2aad restore managed textarea keymap handling (#26771) 2026-05-11 01:45:59 +02:00
Kit LangtonandGitHub 64dde0cb15 Migrate compaction tool-call test (#26737) 2026-05-10 19:44:42 -04:00
Kit LangtonandGitHub a658e43eeb Migrate compaction plugin test (#26736) 2026-05-10 19:42:44 -04:00
Kit LangtonandGitHub ca8a42c973 Migrate LLM compaction tail tests (#26734) 2026-05-10 19:41:28 -04:00
Kit LangtonandGitHub 8f5f75db12 Migrate compaction LLM test (#26733) 2026-05-10 19:20:44 -04:00
Kit LangtonandGitHub 4ff0d07b1d Migrate configurable compaction tests (#26732) 2026-05-10 19:18:02 -04:00
Kit LangtonandGitHub 2a571b3cee Migrate compaction overflow tests (#26731) 2026-05-10 19:12:49 -04:00
DaxandGitHub 0fffcdfe46 Persist session model switches outside event flag (#26765) 2026-05-10 18:53:14 -04:00
DaxandGitHub 2ba2ee52e8 docs: document bun dev tmux capture (#26764) 2026-05-10 17:41:20 -04:00
Frank 56d818fc34 zen: fix reasoning token for openai compatible endpoint 2026-05-10 13:36:02 -04:00
Kit LangtonandGitHub 9c8da69196 Use Effect timeout in compaction test (#26728) 2026-05-10 12:45:54 -04:00
opencode-agent[bot] a78018697c chore: generate 2026-05-10 16:44:40 +00:00
Kit LangtonandGitHub e45b6ef1de refactor(http-recorder): use Schema.TaggedErrorClass for cassette errors (#26729) 2026-05-10 16:43:33 +00:00
opencode-agent[bot] b616543ac2 chore: generate 2026-05-10 16:30:55 +00:00
Kit LangtonandGitHub 2bd3d9a696 refactor(http-recorder): hide cassette format behind Cassette seam (#26725) 2026-05-10 12:29:55 -04:00
Kit LangtonandGitHub fa15dbc5ec Migrate compaction process tests (#26723) 2026-05-10 12:25:44 -04:00
opencode-agent[bot] 312e5c7a7c chore: generate 2026-05-10 16:22:29 +00:00
Kit LangtonandGitHub 049502fac6 fix(server): return diagnosable body for schema rejections (#26631) 2026-05-10 16:21:32 +00:00
opencode-agent[bot] cc2915be16 chore: generate 2026-05-10 16:20:16 +00:00
Kit LangtonandGitHub ce061bf661 Add explicit LLM stream lifecycle events (#26722) 2026-05-10 12:19:13 -04:00
Frank 3b8790e034 zen: fix usage css on mobile 2026-05-10 12:14:11 -04:00
Kit LangtonandGitHub a4f3cedcdf Start effect-style compaction tests 2026-05-10 16:12:00 +00:00
opencode-agent[bot] 1c9a2eb239 chore: generate 2026-05-10 16:06:18 +00:00
Kit LangtonandGitHub 4fb417d3b5 feat(http-recorder): default mode to "auto" (#26719) 2026-05-10 16:05:11 +00:00
Kit LangtonandGitHub 11030c627b Scope boolean query overrides 2026-05-10 11:57:52 -04:00
opencode-agent[bot] c104098a66 chore: generate 2026-05-10 15:55:49 +00:00
Kit LangtonandGitHub 49ee3ba85a Source diff message query pattern (#26638) 2026-05-10 11:54:54 -04:00
opencode-agent[bot] 4fc538378d chore: generate 2026-05-10 14:50:21 +00:00
Kit LangtonandGitHub d28b5ad2f4 refactor(http-recorder): Redactor + Recorder seams, README (#26636) 2026-05-10 10:49:22 -04:00
opencode-agent[bot] 6589a66822 chore: generate 2026-05-10 12:28:11 +00:00
Shoubhit DashandGitHub 5cf9abe743 feat(scout): materialize configured reference repos (#26692) 2026-05-10 17:57:11 +05:30
Frank 903d81819d Zen: add Ring 2.6 1T 2026-05-10 03:51:34 -04:00
opencode-agent[bot] 472f9e64a6 chore: update nix node_modules hashes 2026-05-10 07:06:30 +00:00
Frank c04fa9e253 sync: revert
This reverts commit 3a7f617098.
2026-05-10 02:58:46 -04:00
opencode-agent[bot] 3a78fb1f42 chore: generate 2026-05-10 06:49:21 +00:00
Aiden ClineandGitHub 85ce6a5f95 feat: better image handling (auto resize & max size constraints) (#26401) 2026-05-10 01:48:19 -05:00
opencode-agent[bot] 5217e6c1af chore: generate 2026-05-10 06:39:09 +00:00
Frank 3a7f617098 go: add tencent icon 2026-05-10 02:37:50 -04:00
opencode-agent[bot] d9150413cb chore: generate 2026-05-10 06:24:35 +00:00
JackandGitHub bcbc1dba22 Go add hy3 preview (#26533) 2026-05-10 02:23:34 -04:00
Frank ce3235e115 sync 2026-05-10 02:17:32 -04:00
opencode-agent[bot] a9a2a597d5 chore: generate 2026-05-10 04:30:04 +00:00
DaxandGitHub 3753601f87 Format TUI paths relative to session directory (#26648) 2026-05-10 04:29:02 +00:00
Kit LangtonandGitHub fb4bab8a66 Remove redundant ID Zod overrides (#26633) 2026-05-09 23:12:21 -04:00
opencode-agent[bot] b3526f6ce9 chore: generate 2026-05-10 03:03:37 +00:00
Kit LangtonandGitHub f220f02a2f Source workspace path pattern (#26632) 2026-05-09 23:02:31 -04:00
opencode-agent[bot] 235a86fb60 chore: generate 2026-05-10 02:59:46 +00:00
Kit LangtonandGitHub 67b9c9c027 Source HTTP API ID path patterns (#26623) 2026-05-09 22:58:47 -04:00
opencode 2f11c9f7ed sync release versions for v1.14.46 2026-05-10 02:34:36 +00:00
opencode-agent[bot] e1c1193f3e chore: generate 2026-05-10 02:11:45 +00:00
Kit LangtonandGitHub 29250a0efb fix(session): loosen remaining stored numeric schemas to tolerate legacy data (#26622) 2026-05-09 22:10:48 -04:00
Kit LangtonandGitHub c6e6bdf59f fix(session): tolerate negative token counts in stored parts (#26620) 2026-05-09 22:10:44 -04:00
opencode-agent[bot] d80e1199ca chore: generate 2026-05-10 02:06:39 +00:00
Kit LangtonandGitHub 10ea59066f feat(skill): built-in opencode-meta skill (#26617) 2026-05-09 22:05:37 -04:00
Kit LangtonandGitHub 79d6b10d7c fix(mcp): tolerate output schema ref failures (#26614) 2026-05-09 22:03:59 -04:00
Kit LangtonandGitHub 6e78f36a0f Narrow HTTP API numeric query overrides (#26618) 2026-05-09 22:02:51 -04:00
Kit LangtonandGitHub 16866e1180 Share HTTP API boolean query schema (#26615) 2026-05-09 21:41:15 -04:00
opencode-agent[bot] 6d130e5deb chore: generate 2026-05-10 01:13:41 +00:00
Kit LangtonandGitHub e30d8173c1 Fix OpenAPI workspace query drift (#26609) 2026-05-09 21:12:34 -04:00
opencode 7a79f3a5ea sync release versions for v1.14.45 2026-05-10 00:07:24 +00:00
b8ca71d309 fix(task): subagent inherits parent agent's deny rules (Plan Mode security bypass) (#26597)
Co-authored-by: Developer <temp@example.com>
2026-05-09 23:51:55 +00:00
6849f96825 refactor(provider): share model status schema (#26595)
Co-authored-by: Developer <temp@example.com>
2026-05-09 19:20:31 -04:00
00c3248295 fix(config): allow active provider model status (#26592)
Co-authored-by: Developer <temp@example.com>
2026-05-09 18:59:05 -04:00
opencode-agent[bot] 818b56dbd0 chore: generate 2026-05-09 22:47:54 +00:00
Kit LangtonandGitHub 29b5b24787 fix(tui): aggregate bootstrap request failures
TUI bootstrap now reports all parallel fetch failures together instead of losing sibling failures after the first rejection.
2026-05-09 18:46:52 -04:00
Kit LangtonandGitHub 11363170ca fix(sdk): wrap thrown error bodies in Error
SDK throwOnError paths now convert structured response bodies into real Error instances while preserving the original body and status in cause.
2026-05-09 18:46:43 -04:00
Kit LangtonandGitHub ba9e4b67ed fix(tool/read): match permission patterns against worktree-relative path
Read permission checks now use the same worktree-relative path basis as edit/write/apply_patch, so configured patterns apply consistently.
2026-05-09 18:46:29 -04:00
Kit LangtonandGitHub bd1029b19f test(server): cover HttpApi context inheritance
Adds regression coverage for request context inheritance in promptAsync and explicit context provisioning in stream bodies.
2026-05-09 18:46:10 -04:00
43b51f09d0 fix(httpapi): align runtime query schemas with workspace routing params (#26581)
Co-authored-by: Developer <temp@example.com>
2026-05-09 16:50:30 -04:00
opencode-agent[bot] c61ab51886 chore: generate 2026-05-09 20:45:29 +00:00
d373c562f2 fix(session): accept legacy summary diffs (#26579)
Co-authored-by: Developer <temp@example.com>
2026-05-09 16:44:24 -04:00
opencode-agent[bot] 5fa5d876fc chore: generate 2026-05-09 20:31:32 +00:00
805af011c9 test(session): regression test for #26574 + mirror loosening on Vcs.FileDiff (#26578)
Co-authored-by: Developer <temp@example.com>
2026-05-09 16:30:31 -04:00
opencode-agent[bot] 480aa8b23b chore: generate 2026-05-09 20:24:28 +00:00
OpeOginniandGitHub d62442bb5d fix(sessions): allow optional patch field in diff for migrated sessions (#26574) 2026-05-09 16:23:28 -04:00
Kit LangtonandGitHub 8602937a37 test(session): cover workspace-routed messages (#26576) 2026-05-09 16:19:06 -04:00
77da433e0a fix(session): accept routing params in message list (#26569)
Co-authored-by: Developer <temp@example.com>
2026-05-09 16:02:35 -04:00
opencode-agent[bot] ad79f3e0cf chore: generate 2026-05-09 19:59:00 +00:00
6c2dfd2f52 fix(tui): guard messages.data in session.sync against undefined (#26566)
Co-authored-by: Developer <temp@example.com>
2026-05-09 19:58:03 +00:00
SebastianandGitHub 9a8b54fe62 Plugin command API shim (#26564) 2026-05-09 21:56:49 +02:00
DaxandGitHub dcdbdb218f Move schema utilities into core (#26565) 2026-05-09 19:51:09 +00:00
5e49029e70 fix(provider): isolate plugin model mutations (#26561)
Co-authored-by: Developer <temp@example.com>
2026-05-09 15:47:07 -04:00
opencode 19abadaf27 sync release versions for v1.14.44 2026-05-09 19:33:26 +00:00
1024 changed files with 188153 additions and 96318 deletions
+11 -3
View File
@@ -23,7 +23,7 @@ runs:
fi
- name: Setup Bun
uses: oven-sh/setup-bun@v2
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version-file: ${{ !steps.bun-url.outputs.url && 'package.json' || '' }}
bun-download-url: ${{ steps.bun-url.outputs.url }}
@@ -33,8 +33,9 @@ runs:
shell: bash
run: echo "dir=$(bun pm cache)" >> "$GITHUB_OUTPUT"
- name: Cache Bun dependencies
uses: actions/cache@v4
- name: Restore Bun dependencies
id: bun-cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ steps.cache.outputs.dir }}
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
@@ -56,3 +57,10 @@ runs:
bun install ${{ inputs.install-flags }}
fi
shell: bash
- name: Save Bun dependencies
if: steps.bun-cache.outputs.cache-hit != 'true' && github.event_name != 'pull_request' && github.event_name != 'pull_request_target'
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ steps.cache.outputs.dir }}
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
@@ -19,7 +19,7 @@ runs:
steps:
- name: Create app token
id: apptoken
uses: actions/create-github-app-token@v2
uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2
with:
app-id: ${{ inputs.opencode-app-id }}
private-key: ${{ inputs.opencode-app-secret }}
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0
+2 -2
View File
@@ -12,9 +12,9 @@ jobs:
contents: read
issues: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: oven-sh/setup-bun@v2
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: latest
+50
View File
@@ -0,0 +1,50 @@
name: close-prs
on:
schedule:
- cron: "0 22 * * *" # Daily at 10:00 PM UTC
workflow_dispatch:
inputs:
dry-run:
description: "Log matching PRs without closing them"
type: boolean
default: true
max-close:
description: "Maximum matching PRs to close"
type: string
required: false
default: "50"
jobs:
close:
runs-on: ubuntu-latest
timeout-minutes: 240
permissions:
contents: read
issues: write
pull-requests: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: latest
- name: Close old PRs without enough positive reactions
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
max_close="${{ inputs['max-close'] }}"
if [ -z "$max_close" ]; then
max_close="50"
fi
args=("--threshold" "2" "--age-months" "1" "--sleep-ms" "20000" "--max-close" "$max_close")
if [ "${{ github.event_name }}" = "schedule" ]; then
args+=("--execute")
elif [ "${{ inputs['dry-run'] }}" = "false" ]; then
args+=("--execute")
fi
bun script/github/close-prs.ts "${args[@]}"
-235
View File
@@ -1,235 +0,0 @@
name: close-stale-prs
on:
workflow_dispatch:
inputs:
dryRun:
description: "Log actions without closing PRs"
type: boolean
default: false
schedule:
- cron: "0 6 * * *"
permissions:
contents: read
issues: write
pull-requests: write
jobs:
close-stale-prs:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Close inactive PRs
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const DAYS_INACTIVE = 60
const MAX_RETRIES = 3
// Adaptive delay: fast for small batches, slower for large to respect
// GitHub's 80 content-generating requests/minute limit
const SMALL_BATCH_THRESHOLD = 10
const SMALL_BATCH_DELAY_MS = 1000 // 1s for daily operations (≤10 PRs)
const LARGE_BATCH_DELAY_MS = 2000 // 2s for backlog (>10 PRs) = ~30 ops/min, well under 80 limit
const startTime = Date.now()
const cutoff = new Date(Date.now() - DAYS_INACTIVE * 24 * 60 * 60 * 1000)
const { owner, repo } = context.repo
const dryRun = context.payload.inputs?.dryRun === "true"
core.info(`Dry run mode: ${dryRun}`)
core.info(`Cutoff date: ${cutoff.toISOString()}`)
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
async function withRetry(fn, description = 'API call') {
let lastError
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
try {
const result = await fn()
return result
} catch (error) {
lastError = error
const isRateLimited = error.status === 403 &&
(error.message?.includes('rate limit') || error.message?.includes('secondary'))
if (!isRateLimited) {
throw error
}
// Parse retry-after header, default to 60 seconds
const retryAfter = error.response?.headers?.['retry-after']
? parseInt(error.response.headers['retry-after'])
: 60
// Exponential backoff: retryAfter * 2^attempt
const backoffMs = retryAfter * 1000 * Math.pow(2, attempt)
core.warning(`${description}: Rate limited (attempt ${attempt + 1}/${MAX_RETRIES}). Waiting ${backoffMs / 1000}s before retry...`)
await sleep(backoffMs)
}
}
core.error(`${description}: Max retries (${MAX_RETRIES}) exceeded`)
throw lastError
}
const query = `
query($owner: String!, $repo: String!, $cursor: String) {
repository(owner: $owner, name: $repo) {
pullRequests(first: 100, states: OPEN, after: $cursor) {
pageInfo {
hasNextPage
endCursor
}
nodes {
number
title
author {
login
}
createdAt
commits(last: 1) {
nodes {
commit {
committedDate
}
}
}
comments(last: 1) {
nodes {
createdAt
}
}
reviews(last: 1) {
nodes {
createdAt
}
}
}
}
}
}
`
const allPrs = []
let cursor = null
let hasNextPage = true
let pageCount = 0
while (hasNextPage) {
pageCount++
core.info(`Fetching page ${pageCount} of open PRs...`)
const result = await withRetry(
() => github.graphql(query, { owner, repo, cursor }),
`GraphQL page ${pageCount}`
)
allPrs.push(...result.repository.pullRequests.nodes)
hasNextPage = result.repository.pullRequests.pageInfo.hasNextPage
cursor = result.repository.pullRequests.pageInfo.endCursor
core.info(`Page ${pageCount}: fetched ${result.repository.pullRequests.nodes.length} PRs (total: ${allPrs.length})`)
// Delay between pagination requests (use small batch delay for reads)
if (hasNextPage) {
await sleep(SMALL_BATCH_DELAY_MS)
}
}
core.info(`Found ${allPrs.length} open pull requests`)
const stalePrs = allPrs.filter((pr) => {
const dates = [
new Date(pr.createdAt),
pr.commits.nodes[0] ? new Date(pr.commits.nodes[0].commit.committedDate) : null,
pr.comments.nodes[0] ? new Date(pr.comments.nodes[0].createdAt) : null,
pr.reviews.nodes[0] ? new Date(pr.reviews.nodes[0].createdAt) : null,
].filter((d) => d !== null)
const lastActivity = dates.sort((a, b) => b.getTime() - a.getTime())[0]
if (!lastActivity || lastActivity > cutoff) {
core.info(`PR #${pr.number} is fresh (last activity: ${lastActivity?.toISOString() || "unknown"})`)
return false
}
core.info(`PR #${pr.number} is STALE (last activity: ${lastActivity.toISOString()})`)
return true
})
if (!stalePrs.length) {
core.info("No stale pull requests found.")
return
}
core.info(`Found ${stalePrs.length} stale pull requests`)
// ============================================
// Close stale PRs
// ============================================
const requestDelayMs = stalePrs.length > SMALL_BATCH_THRESHOLD
? LARGE_BATCH_DELAY_MS
: SMALL_BATCH_DELAY_MS
core.info(`Using ${requestDelayMs}ms delay between operations (${stalePrs.length > SMALL_BATCH_THRESHOLD ? 'large' : 'small'} batch mode)`)
let closedCount = 0
let skippedCount = 0
for (const pr of stalePrs) {
const issue_number = pr.number
const closeComment = `Closing this pull request because it has had no updates for more than ${DAYS_INACTIVE} days. If you plan to continue working on it, feel free to reopen or open a new PR.`
if (dryRun) {
core.info(`[dry-run] Would close PR #${issue_number} from ${pr.author?.login || 'unknown'}: ${pr.title}`)
continue
}
try {
// Add comment
await withRetry(
() => github.rest.issues.createComment({
owner,
repo,
issue_number,
body: closeComment,
}),
`Comment on PR #${issue_number}`
)
// Close PR
await withRetry(
() => github.rest.pulls.update({
owner,
repo,
pull_number: issue_number,
state: "closed",
}),
`Close PR #${issue_number}`
)
closedCount++
core.info(`Closed PR #${issue_number} from ${pr.author?.login || 'unknown'}: ${pr.title}`)
// Delay before processing next PR
await sleep(requestDelayMs)
} catch (error) {
skippedCount++
core.error(`Failed to close PR #${issue_number}: ${error.message}`)
}
}
const elapsed = Math.round((Date.now() - startTime) / 1000)
core.info(`\n========== Summary ==========`)
core.info(`Total open PRs found: ${allPrs.length}`)
core.info(`Stale PRs identified: ${stalePrs.length}`)
core.info(`PRs closed: ${closedCount}`)
core.info(`PRs skipped (errors): ${skippedCount}`)
core.info(`Elapsed time: ${elapsed}s`)
core.info(`=============================`)
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Close non-compliant issues and PRs after 2 hours
uses: actions/github-script@v7
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
const { data: items } = await github.rest.issues.listForRepo({
+4 -4
View File
@@ -21,18 +21,18 @@ jobs:
REGISTRY: ghcr.io/${{ github.repository_owner }}
TAG: "24.04"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: ./.github/actions/setup-bun
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Login to GHCR
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
+2 -2
View File
@@ -13,11 +13,11 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: ./.github/actions/setup-bun
- uses: actions/setup-node@v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
fetch-depth: 0
+2 -2
View File
@@ -18,7 +18,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0 # Fetch full history to access commits
@@ -43,7 +43,7 @@ jobs:
- name: Run opencode
if: steps.commits.outputs.has_commits == 'true'
uses: sst/opencode/github@latest
uses: sst/opencode/github@2c14fc5586fe0b88e5c04732d2e846769cc35671 # latest
env:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
with:
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 1
@@ -125,7 +125,7 @@ jobs:
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 1
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Setup Bun
uses: ./.github/actions/setup-bun
+2 -2
View File
@@ -20,10 +20,10 @@ jobs:
timeout-minutes: 15
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Nix
uses: nixbuild/nix-quick-install-action@v34
uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
- name: Evaluate flake outputs (all systems)
run: |
+5 -5
View File
@@ -41,10 +41,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Nix
uses: nixbuild/nix-quick-install-action@v34
uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
- name: Compute node_modules hash
id: hash
@@ -72,7 +72,7 @@ jobs:
echo "Computed hash for ${SYSTEM}: $HASH"
- name: Upload hash
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: hash-${{ matrix.system }}
path: hash.txt
@@ -85,7 +85,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
fetch-depth: 0
@@ -102,7 +102,7 @@ jobs:
git pull --rebase --autostash origin "$GITHUB_REF_NAME"
- name: Download hash artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
path: hashes
pattern: hash-*
+1 -1
View File
@@ -9,6 +9,6 @@ jobs:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Send nicely-formatted embed to Discord
uses: SethCohen/github-releases-to-discord@v1
uses: SethCohen/github-releases-to-discord@24d166886aee4646d448c8a389ff9e1ebcab3682 # v1.20.0
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
+2 -2
View File
@@ -21,12 +21,12 @@ jobs:
issues: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- uses: ./.github/actions/setup-bun
- name: Run opencode
uses: anomalyco/opencode/github@latest
uses: anomalyco/opencode/github@2c14fc5586fe0b88e5c04732d2e846769cc35671 # latest
env:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
OPENCODE_PERMISSION: '{"bash": "deny"}'
+2 -2
View File
@@ -12,7 +12,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 1
@@ -78,7 +78,7 @@ jobs:
issues: write
steps:
- name: Add Contributor Label
uses: actions/github-script@v8
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const isPR = !!context.payload.pull_request;
+2 -2
View File
@@ -12,7 +12,7 @@ jobs:
pull-requests: write
steps:
- name: Check PR standards
uses: actions/github-script@v7
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
const pr = context.payload.pull_request;
@@ -159,7 +159,7 @@ jobs:
pull-requests: write
steps:
- name: Check PR template compliance
uses: actions/github-script@v7
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
const pr = context.payload.pull_request;
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
publish:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
fetch-depth: 0
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
publish:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
fetch-depth: 0
+29 -28
View File
@@ -7,6 +7,7 @@ on:
- ci
- dev
- beta
- fix/npm-native-binary-install
- snapshot-*
workflow_dispatch:
inputs:
@@ -35,7 +36,7 @@ jobs:
runs-on: blacksmith-4vcpu-ubuntu-2404
if: github.repository == 'anomalyco/opencode'
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
fetch-depth: 0
@@ -72,7 +73,7 @@ jobs:
runs-on: blacksmith-4vcpu-ubuntu-2404
if: github.repository == 'anomalyco/opencode'
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
fetch-tags: true
@@ -95,14 +96,14 @@ jobs:
GH_REPO: ${{ needs.version.outputs.repo }}
GH_TOKEN: ${{ steps.committer.outputs.token }}
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: opencode-cli
path: |
packages/opencode/dist/opencode-darwin*
packages/opencode/dist/opencode-linux*
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: opencode-cli-windows
path: packages/opencode/dist/opencode-windows*
@@ -123,9 +124,9 @@ jobs:
AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE: ${{ secrets.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE }}
AZURE_TRUSTED_SIGNING_ENDPOINT: ${{ secrets.AZURE_TRUSTED_SIGNING_ENDPOINT }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: opencode-cli-windows
path: packages/opencode/dist
@@ -138,13 +139,13 @@ jobs:
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Azure login
uses: azure/login@v2
uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0
with:
client-id: ${{ env.AZURE_CLIENT_ID }}
tenant-id: ${{ env.AZURE_TENANT_ID }}
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
- uses: azure/artifact-signing-action@v1
- uses: azure/artifact-signing-action@b443cf8ea4124818d2ea9f043cba29fc3ec47b16 # v1.2.0
with:
endpoint: ${{ env.AZURE_TRUSTED_SIGNING_ENDPOINT }}
signing-account-name: ${{ env.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
@@ -201,7 +202,7 @@ jobs:
--clobber `
--repo "${{ needs.version.outputs.repo }}"
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: opencode-cli-signed-windows
path: |
@@ -244,14 +245,14 @@ jobs:
- host: "blacksmith-4vcpu-ubuntu-2404"
target: x86_64-unknown-linux-gnu
platform_flag: --linux
- host: "blacksmith-4vcpu-ubuntu-2404"
- host: "blacksmith-4vcpu-ubuntu-2404-arm"
target: aarch64-unknown-linux-gnu
platform_flag: --linux
platform_flag: --linux --arm64
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: apple-actions/import-codesign-certs@v2
- uses: apple-actions/import-codesign-certs@8f3fb608891dd2244cdab3d69cd68c0d37a7fe93 # v2.0.0
if: runner.os == 'macOS'
with:
keychain: build
@@ -268,19 +269,19 @@ jobs:
- name: Azure login
if: runner.os == 'Windows'
uses: azure/login@v2
uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0
with:
client-id: ${{ env.AZURE_CLIENT_ID }}
tenant-id: ${{ env.AZURE_TENANT_ID }}
subscription-id: ${{ env.AZURE_SUBSCRIPTION_ID }}
- uses: actions/setup-node@v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
- name: Cache apt packages
if: contains(matrix.settings.host, 'ubuntu')
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ~/apt-cache
key: ${{ runner.os }}-${{ matrix.settings.target }}-apt-electron-${{ hashFiles('.github/workflows/publish.yml') }}
@@ -388,12 +389,12 @@ jobs:
}
}
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: opencode-desktop-${{ matrix.settings.target }}
path: packages/desktop/dist/*
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: needs.version.outputs.release
with:
name: latest-yml-${{ matrix.settings.target }}
@@ -408,44 +409,44 @@ jobs:
if: always() && !failure() && !cancelled()
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: ./.github/actions/setup-bun
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- uses: actions/setup-node@v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: opencode-cli
path: packages/opencode/dist
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: opencode-cli-windows
path: packages/opencode/dist
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: opencode-cli-signed-windows
path: packages/opencode/dist
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
if: needs.version.outputs.release
with:
pattern: latest-yml-*
@@ -459,7 +460,7 @@ jobs:
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Cache apt packages (AUR)
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: /var/cache/apt/archives
key: ${{ runner.os }}-apt-aur-${{ hashFiles('.github/workflows/publish.yml') }}
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
release:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
fi
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 1
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Setup Bun
uses: ./.github/actions/setup-bun
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Setup Bun
uses: ./.github/actions/setup-bun
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
name: Release Zed Extension
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0
+9 -9
View File
@@ -37,12 +37,12 @@ jobs:
shell: bash
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
@@ -55,7 +55,7 @@ jobs:
git config --global user.name "opencode"
- name: Cache Turbo
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: node_modules/.cache/turbo
key: turbo-${{ runner.os }}-${{ hashFiles('turbo.json', '**/package.json') }}-${{ github.sha }}
@@ -75,7 +75,7 @@ jobs:
- name: Publish unit reports
if: always()
uses: mikepenz/action-junit-report@v6
uses: mikepenz/action-junit-report@bccf2e31636835cf0874589931c4116687171386 # v6.4.0
with:
report_paths: packages/*/.artifacts/unit/junit.xml
check_name: "unit results (${{ matrix.settings.name }})"
@@ -85,7 +85,7 @@ jobs:
- name: Upload unit artifacts
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: unit-${{ matrix.settings.name }}-${{ github.run_attempt }}
include-hidden-files: true
@@ -111,12 +111,12 @@ jobs:
shell: bash
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "24"
@@ -131,7 +131,7 @@ jobs:
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ github.workspace }}/.playwright-browsers
key: ${{ runner.os }}-${{ runner.arch }}-playwright-${{ steps.playwright-version.outputs.version }}-chromium
@@ -155,7 +155,7 @@ jobs:
- name: Upload Playwright artifacts
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: playwright-${{ matrix.settings.name }}-${{ github.run_attempt }}
if-no-files-found: ignore
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 1
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Setup Bun
uses: ./.github/actions/setup-bun
+1 -5
View File
@@ -1,11 +1,7 @@
{
"$schema": "https://opencode.ai/config.json",
"provider": {},
"permission": {
"edit": {
"packages/opencode/migration/*": "ask",
},
},
"permission": {},
"mcp": {},
"tools": {
"github-triage": false,
@@ -0,0 +1,37 @@
# Deepening
How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [LANGUAGE.md](LANGUAGE.md) — **module**, **interface**, **seam**, **adapter**.
## Dependency categories
When assessing a candidate for deepening, classify its dependencies. The category determines how the deepened module is tested across its seam.
### 1. In-process
Pure computation, in-memory state, no I/O. Always deepenable — merge the modules and test through the new interface directly. No adapter needed.
### 2. Local-substitutable
Dependencies that have local test stand-ins (PGLite for Postgres, in-memory filesystem). Deepenable if the stand-in exists. The deepened module is tested with the stand-in running in the test suite. The seam is internal; no port at the module's external interface.
### 3. Remote but owned (Ports & Adapters)
Your own services across a network boundary (microservices, internal APIs). Define a **port** (interface) at the seam. The deep module owns the logic; the transport is injected as an **adapter**. Tests use an in-memory adapter. Production uses an HTTP/gRPC/queue adapter.
Recommendation shape: _"Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it's deployed across a network."_
### 4. True external (Mock)
Third-party services (Stripe, Twilio, etc.) you don't control. The deepened module takes the external dependency as an injected port; tests provide a mock adapter.
## Seam discipline
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection.
- **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them.
## Testing strategy: replace, don't layer
- Old unit tests on shallow modules become waste once tests at the deepened module's interface exist — delete them.
- Write new tests at the deepened module's interface. The **interface is the test surface**.
- Tests assert on observable outcomes through the interface, not internal state.
- Tests should survive internal refactors — they describe behaviour, not implementation. If a test has to change when the implementation changes, it's testing past the interface.
@@ -0,0 +1,44 @@
# Interface Design
When the user wants to explore alternative interfaces for a chosen deepening candidate, use this parallel sub-agent pattern. Based on "Design It Twice" (Ousterhout) — your first idea is unlikely to be the best.
Uses the vocabulary in [LANGUAGE.md](LANGUAGE.md) — **module**, **interface**, **seam**, **adapter**, **leverage**.
## Process
### 1. Frame the problem space
Before spawning sub-agents, write a user-facing explanation of the problem space for the chosen candidate:
- The constraints any new interface would need to satisfy
- The dependencies it would rely on, and which category they fall into (see [DEEPENING.md](DEEPENING.md))
- A rough illustrative code sketch to ground the constraints — not a proposal, just a way to make the constraints concrete
Show this to the user, then immediately proceed to Step 2. The user reads and thinks while the sub-agents work in parallel.
### 2. Spawn sub-agents
Spawn 3+ sub-agents in parallel using the Agent tool. Each must produce a **radically different** interface for the deepened module.
Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [DEEPENING.md](DEEPENING.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint:
- Agent 1: "Minimize the interface — aim for 13 entry points max. Maximise leverage per entry point."
- Agent 2: "Maximise flexibility — support many use cases and extension."
- Agent 3: "Optimise for the most common caller — make the default case trivial."
- Agent 4 (if applicable): "Design around ports & adapters for cross-seam dependencies."
Include both [LANGUAGE.md](LANGUAGE.md) vocabulary and CONTEXT.md vocabulary in the brief so each sub-agent names things consistently with the architecture language and the project's domain language.
Each sub-agent outputs:
1. Interface (types, methods, params — plus invariants, ordering, error modes)
2. Usage example showing how callers use it
3. What the implementation hides behind the seam
4. Dependency strategy and adapters (see [DEEPENING.md](DEEPENING.md))
5. Trade-offs — where leverage is high, where it's thin
### 3. Present and compare
Present designs sequentially so the user can absorb each one, then compare them in prose. Contrast by **depth** (leverage at the interface), **locality** (where change concentrates), and **seam placement**.
After comparing, give your own recommendation: which design you think is strongest and why. If elements from different designs would combine well, propose a hybrid. Be opinionated — the user wants a strong read, not a menu.
@@ -0,0 +1,53 @@
# Language
Shared vocabulary for every suggestion this skill makes. Use these terms exactly — don't substitute "component," "service," "API," or "boundary." Consistent language is the whole point.
## Terms
**Module**
Anything with an interface and an implementation. Deliberately scale-agnostic — applies equally to a function, class, package, or tier-spanning slice.
_Avoid_: unit, component, service.
**Interface**
Everything a caller must know to use the module correctly. Includes the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics.
_Avoid_: API, signature (too narrow — those refer only to the type-level surface).
**Implementation**
What's inside a module — its body of code. Distinct from **Adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise.
**Depth**
Leverage at the interface — the amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is **deep** when a large amount of behaviour sits behind a small interface. A module is **shallow** when the interface is nearly as complex as the implementation.
**Seam** _(from Michael Feathers)_
A place where you can alter behaviour without editing in that place. The _location_ at which a module's interface lives. Choosing where to put the seam is its own design decision, distinct from what goes behind it.
_Avoid_: boundary (overloaded with DDD's bounded context).
**Adapter**
A concrete thing that satisfies an interface at a seam. Describes _role_ (what slot it fills), not substance (what's inside).
**Leverage**
What callers get from depth. More capability per unit of interface they have to learn. One implementation pays back across N call sites and M tests.
**Locality**
What maintainers get from depth. Change, bugs, knowledge, and verification concentrate at one place rather than spreading across callers. Fix once, fixed everywhere.
## Principles
- **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface.
- **The deletion test.** Imagine deleting the module. If complexity vanishes, the module wasn't hiding anything (it was a pass-through). If complexity reappears across N callers, the module was earning its keep.
- **The interface is the test surface.** Callers and tests cross the same seam. If you want to test _past_ the interface, the module is probably the wrong shape.
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it.
## Relationships
- A **Module** has exactly one **Interface** (the surface it presents to callers and tests).
- **Depth** is a property of a **Module**, measured against its **Interface**.
- A **Seam** is where a **Module**'s **Interface** lives.
- An **Adapter** sits at a **Seam** and satisfies the **Interface**.
- **Depth** produces **Leverage** for callers and **Locality** for maintainers.
## Rejected framings
- **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead.
- **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow — interface here includes every fact a caller must know.
- **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**.
@@ -0,0 +1,71 @@
---
name: improve-codebase-architecture
description: Find deepening opportunities in a codebase, informed by the domain language in CONTEXT.md and the decisions in docs/adr/. Use when the user wants to improve architecture, find refactoring opportunities, consolidate tightly-coupled modules, or make a codebase more testable and AI-navigable.
---
# Improve Codebase Architecture
Surface architectural friction and propose **deepening opportunities** — refactors that turn shallow modules into deep ones. The aim is testability and AI-navigability.
## Glossary
Use these terms exactly in every suggestion. Consistent language is the point — don't drift into "component," "service," "API," or "boundary." Full definitions in [LANGUAGE.md](LANGUAGE.md).
- **Module** — anything with an interface and an implementation (function, class, package, slice).
- **Interface** — everything a caller must know to use the module: types, invariants, error modes, ordering, config. Not just the type signature.
- **Implementation** — the code inside.
- **Depth** — leverage at the interface: a lot of behaviour behind a small interface. **Deep** = high leverage. **Shallow** = interface nearly as complex as the implementation.
- **Seam** — where an interface lives; a place behaviour can be altered without editing in place. (Use this, not "boundary.")
- **Adapter** — a concrete thing satisfying an interface at a seam.
- **Leverage** — what callers get from depth.
- **Locality** — what maintainers get from depth: change, bugs, knowledge concentrated in one place.
Key principles (see [LANGUAGE.md](LANGUAGE.md) for the full list):
- **Deletion test**: imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.
- **The interface is the test surface.**
- **One adapter = hypothetical seam. Two adapters = real seam.**
This skill is _informed_ by the project's domain model. The domain language gives names to good seams; ADRs record decisions the skill should not re-litigate.
## Process
### 1. Explore
Read the project's domain glossary and any ADRs in the area you're touching first.
Then use the Agent tool with `subagent_type=Explore` to walk the codebase. Don't follow rigid heuristics — explore organically and note where you experience friction:
- Where does understanding one concept require bouncing between many small modules?
- Where are modules **shallow** — interface nearly as complex as the implementation?
- Where have pure functions been extracted just for testability, but the real bugs hide in how they're called (no **locality**)?
- Where do tightly-coupled modules leak across their seams?
- Which parts of the codebase are untested, or hard to test through their current interface?
Apply the **deletion test** to anything you suspect is shallow: would deleting it concentrate complexity, or just move it? A "yes, concentrates" is the signal you want.
### 2. Present candidates
Present a numbered list of deepening opportunities. For each candidate:
- **Files** — which files/modules are involved
- **Problem** — why the current architecture is causing friction
- **Solution** — plain English description of what would change
- **Benefits** — explained in terms of locality and leverage, and also in how tests would improve
**Use CONTEXT.md vocabulary for the domain, and [LANGUAGE.md](LANGUAGE.md) vocabulary for the architecture.** If `CONTEXT.md` defines "Order," talk about "the Order intake module" — not "the FooBarHandler," and not "the Order service."
**ADR conflicts**: if a candidate contradicts an existing ADR, only surface it when the friction is real enough to warrant revisiting the ADR. Mark it clearly (e.g. _"contradicts ADR-0007 — but worth reopening because…"_). Don't list every theoretical refactor an ADR forbids.
Do NOT propose interfaces yet. Ask the user: "Which of these would you like to explore?"
### 3. Grilling loop
Once the user picks a candidate, drop into a grilling conversation. Walk the design tree with them — constraints, dependencies, the shape of the deepened module, what sits behind the seam, what tests survive.
Side effects happen inline as decisions crystallize:
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as `/grill-with-docs` (see [CONTEXT-FORMAT.md](../grill-with-docs/CONTEXT-FORMAT.md)). Create the file lazily if it doesn't exist.
- **Sharpening a fuzzy term during the conversation?** Update `CONTEXT.md` right there.
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See [ADR-FORMAT.md](../grill-with-docs/ADR-FORMAT.md).
- **Want to explore alternative interfaces for the deepened module?** See [INTERFACE-DESIGN.md](INTERFACE-DESIGN.md).
+24
View File
@@ -9,6 +9,7 @@
### General Principles
- Keep things in one function unless composable or reusable
- Do not extract single-use helpers preemptively. Inline the logic at the call site unless the helper is reused, hides a genuinely complex boundary, or has a clear independent name that improves the caller.
- Avoid `try`/`catch` where possible
- Avoid using the `any` type
- Use Bun APIs when possible, like `Bun.file()`
@@ -72,6 +73,29 @@ function foo() {
}
```
### Complex Logic
When a function has several validation branches or supporting details, make the main function read as the happy path and move supporting details into small helpers below it.
```ts
// Good
export function loadThing(input: unknown) {
const config = requireConfig(input)
const metadata = readMetadata(input)
return createThing({ config, metadata })
}
function requireConfig(input: unknown) {
...
}
```
- Keep helpers close to the code they support, below the main export when that improves readability.
- Do not over-abstract simple expressions into many single-use helpers; extract only when it names a real concept like `requireConfig` or `readMetadata`.
- Do not return `Effect` from helpers unless they actually perform effectful work. Synchronous parsing, validation, and option building should stay synchronous.
- Prefer Effect schema helpers such as `Schema.UnknownFromJsonString` and `Schema.decodeUnknownOption` over manual `JSON.parse` wrapped in `Effect.try` when parsing untrusted JSON strings.
- Add comments for non-obvious constraints and surprising behavior, not for obvious assignments or control flow.
### Schema Definitions (Drizzle)
Use snake_case for field names so column names don't need to be redefined as strings.
-12
View File
@@ -124,18 +124,6 @@ XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash
اذا كنت تعمل على مشروع مرتبط بـ OpenCode ويستخدم "opencode" كجزء من اسمه (مثل "opencode-dashboard" او "opencode-mobile")، يرجى اضافة ملاحظة في README توضح انه ليس مبنيا بواسطة فريق OpenCode ولا يرتبط بنا بأي شكل.
### FAQ
#### ما الفرق عن Claude Code؟
هو مشابه جدا لـ Claude Code من حيث القدرات. هذه هي الفروقات الاساسية:
- 100% مفتوح المصدر
- غير مقترن بمزود معين. نوصي بالنماذج التي نوفرها عبر [OpenCode Zen](https://opencode.ai/zen)؛ لكن يمكن استخدام OpenCode مع Claude او OpenAI او Google او حتى نماذج محلية. مع تطور النماذج ستتقلص الفجوات وستنخفض الاسعار، لذا من المهم ان يكون مستقلا عن المزود.
- دعم LSP جاهز للاستخدام
- تركيز على TUI. تم بناء OpenCode بواسطة مستخدمي neovim ومنشئي [terminal.shop](https://terminal.shop)؛ وسندفع حدود ما هو ممكن داخل الطرفية.
- معمارية عميل/خادم. على سبيل المثال، يمكن تشغيل OpenCode على جهازك بينما تقوده عن بعد من تطبيق جوال. هذا يعني ان واجهة TUI هي واحدة فقط من العملاء الممكنين.
---
**انضم الى مجتمعنا** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ OpenCode এ দুটি বিল্ট-ইন এজেন্ট রয়ে
আপনি যদি এমন প্রজেক্টে কাজ করেন যা OpenCode এর সাথে সম্পর্কিত এবং প্রজেক্টের নামের অংশ হিসেবে "opencode" ব্যবহার করেন, উদাহরণস্বরূপ "opencode-dashboard" বা "opencode-mobile", তবে দয়া করে আপনার README তে একটি নোট যোগ করে স্পষ্ট করুন যে এই প্রজেক্টটি OpenCode দল দ্বারা তৈরি হয়নি এবং আমাদের সাথে এর কোনো সরাসরি সম্পর্ক নেই।
### সচরাচর জিজ্ঞাসিত প্রশ্নাবলী (FAQ)
#### এটি ক্লড কোড (Claude Code) থেকে কীভাবে আলাদা?
ক্যাপাবিলিটির দিক থেকে এটি ক্লড কোডের (Claude Code) মতই। এখানে মূল পার্থক্যগুলো দেওয়া হলো:
- ১০০% ওপেন সোর্স
- কোনো প্রোভাইডারের সাথে আবদ্ধ নয়। যদিও আমরা [OpenCode Zen](https://opencode.ai/zen) এর মাধ্যমে মডেলসমূহ ব্যবহারের পরামর্শ দিই, OpenCode ক্লড (Claude), ওপেনএআই (OpenAI), গুগল (Google), অথবা লোকাল মডেলগুলোর সাথেও ব্যবহার করা যেতে পারে। যেমন যেমন মডেলগুলো উন্নত হবে, তাদের মধ্যকার পার্থক্য কমে আসবে এবং দামও কমবে, তাই প্রোভাইডার-অজ্ঞাস্টিক হওয়া খুবই গুরুত্বপূর্ণ।
- আউট-অফ-দ্য-বক্স LSP সাপোর্ট
- TUI এর উপর ফোকাস। OpenCode নিওভিম (neovim) ব্যবহারকারী এবং [terminal.shop](https://terminal.shop) এর নির্মাতাদের দ্বারা তৈরি; আমরা টার্মিনালে কী কী সম্ভব তার সীমাবদ্ধতা ছাড়িয়ে যাওয়ার চেষ্টা করছি।
- ক্লায়েন্ট/সার্ভার আর্কিটেকচার। এটি যেমন OpenCode কে আপনার কম্পিউটারে চালানোর সুযোগ দেয়, তেমনি আপনি মোবাইল অ্যাপ থেকে রিমোটলি এটি নিয়ন্ত্রণ করতে পারবেন, অর্থাৎ TUI ফ্রন্টএন্ড কেবল সম্ভাব্য ক্লায়েন্টগুলোর মধ্যে একটি।
---
**আমাদের কমিউনিটিতে যুক্ত হোন** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ Se você tem interesse em contribuir com o OpenCode, leia os [contributing docs]
Se você estiver trabalhando em um projeto relacionado ao OpenCode e estiver usando "opencode" como parte do nome (por exemplo, "opencode-dashboard" ou "opencode-mobile"), adicione uma nota no README para deixar claro que não foi construído pela equipe do OpenCode e não é afiliado a nós de nenhuma forma.
### FAQ
#### Como isso é diferente do Claude Code?
É muito parecido com o Claude Code em termos de capacidade. Aqui estão as principais diferenças:
- 100% open source
- Não está acoplado a nenhum provedor. Embora recomendemos os modelos que oferecemos pelo [OpenCode Zen](https://opencode.ai/zen); o OpenCode pode ser usado com Claude, OpenAI, Google ou até modelos locais. À medida que os modelos evoluem, as diferenças diminuem e os preços caem, então ser provider-agnostic é importante.
- Suporte a LSP pronto para uso
- Foco em TUI. O OpenCode é construído por usuários de neovim e pelos criadores do [terminal.shop](https://terminal.shop); vamos levar ao limite o que é possível no terminal.
- Arquitetura cliente/servidor. Isso, por exemplo, permite executar o OpenCode no seu computador enquanto você o controla remotamente por um aplicativo mobile. Isso significa que o frontend TUI é apenas um dos possíveis clientes.
---
**Junte-se à nossa comunidade** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ Ako želiš doprinositi OpenCode-u, pročitaj [upute za doprinošenje](./CONTRIB
Ako radiš na projektu koji je povezan s OpenCode-om i koristi "opencode" kao dio naziva, npr. "opencode-dashboard" ili "opencode-mobile", dodaj napomenu u svoj README da projekat nije napravio OpenCode tim i da nije povezan s nama.
### FAQ
#### Po čemu se razlikuje od Claude Code-a?
Po mogućnostima je vrlo sličan Claude Code-u. Ključne razlike su:
- 100% open source
- Nije vezan za jednog provajdera. Iako preporučujemo modele koje nudimo kroz [OpenCode Zen](https://opencode.ai/zen), OpenCode možeš koristiti s Claude, OpenAI, Google ili čak lokalnim modelima. Kako modeli napreduju, razlike među njima će se smanjivati, a cijene padati, zato je nezavisnost od provajdera važna.
- LSP podrška odmah po instalaciji
- Fokus na TUI. OpenCode grade neovim korisnici i kreatori [terminal.shop](https://terminal.shop); pomjeraćemo granice onoga što je moguće u terminalu.
- Klijent/server arhitektura. To, recimo, omogućava da OpenCode radi na tvom računaru dok ga daljinski koristiš iz mobilne aplikacije, što znači da je TUI frontend samo jedan od mogućih klijenata.
---
**Pridruži se našoj zajednici** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ Hvis du vil bidrage til OpenCode, så læs vores [contributing docs](./CONTRIBUT
Hvis du arbejder på et projekt der er relateret til OpenCode og bruger "opencode" som en del af navnet; f.eks. "opencode-dashboard" eller "opencode-mobile", så tilføj en note i din README, der tydeliggør at projektet ikke er bygget af OpenCode-teamet og ikke er tilknyttet os på nogen måde.
### FAQ
#### Hvordan adskiller dette sig fra Claude Code?
Det minder meget om Claude Code i forhold til funktionalitet. Her er de vigtigste forskelle:
- 100% open source
- Ikke låst til en udbyder. Selvom vi anbefaler modellerne via [OpenCode Zen](https://opencode.ai/zen); kan OpenCode bruges med Claude, OpenAI, Google eller endda lokale modeller. Efterhånden som modeller udvikler sig vil forskellene mindskes og priserne falde, så det er vigtigt at være provider-agnostic.
- LSP-support out of the box
- Fokus på TUI. OpenCode er bygget af neovim-brugere og skaberne af [terminal.shop](https://terminal.shop); vi vil skubbe grænserne for hvad der er muligt i terminalen.
- Klient/server-arkitektur. Det kan f.eks. lade OpenCode køre på din computer, mens du styrer den eksternt fra en mobilapp. Det betyder at TUI-frontend'en kun er en af de mulige clients.
---
**Bliv en del af vores community** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ Wenn du zu OpenCode beitragen möchtest, lies bitte unsere [Contributing Docs](.
Wenn du an einem Projekt arbeitest, das mit OpenCode zusammenhängt und "opencode" als Teil seines Namens verwendet (z.B. "opencode-dashboard" oder "opencode-mobile"), füge bitte einen Hinweis in deine README ein, dass es nicht vom OpenCode-Team gebaut wird und nicht in irgendeiner Weise mit uns verbunden ist.
### FAQ
#### Worin unterscheidet sich das von Claude Code?
In Bezug auf die Fähigkeiten ist es Claude Code sehr ähnlich. Hier sind die wichtigsten Unterschiede:
- 100% open source
- Nicht an einen Anbieter gekoppelt. Wir empfehlen die Modelle aus [OpenCode Zen](https://opencode.ai/zen); OpenCode kann aber auch mit Claude, OpenAI, Google oder sogar lokalen Modellen genutzt werden. Mit der Weiterentwicklung der Modelle werden die Unterschiede kleiner und die Preise sinken, deshalb ist Provider-Unabhängigkeit wichtig.
- LSP-Unterstützung direkt nach dem Start
- Fokus auf TUI. OpenCode wird von Neovim-Nutzern und den Machern von [terminal.shop](https://terminal.shop) gebaut; wir treiben die Grenzen dessen, was im Terminal möglich ist.
- Client/Server-Architektur. Das ermöglicht z.B., OpenCode auf deinem Computer laufen zu lassen, während du es von einer mobilen App aus fernsteuerst. Das TUI-Frontend ist nur einer der möglichen Clients.
---
**Tritt unserer Community bei** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
+9 -21
View File
@@ -97,20 +97,20 @@ OPENCODE_INSTALL_DIR=/usr/local/bin curl -fsSL https://opencode.ai/install | bas
XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash
```
### Agents
### Agentes
OpenCode incluye dos agents integrados que puedes alternar con la tecla `Tab`.
OpenCode incluye dos agentes integrados que puedes alternar con la tecla `Tab`.
- **build** - Por defecto, agent con acceso completo para trabajo de desarrollo
- **plan** - Agent de solo lectura para análisis y exploración de código
- Niega ediciones de archivos por defecto
- **build** - Por defecto, agente con acceso completo para tareas de desarrollo
- **plan** - Agente de solo lectura para análisis y exploración de código
- Deniega ediciones de archivos por defecto
- Pide permiso antes de ejecutar comandos bash
- Ideal para explorar codebases desconocidas o planificar cambios
Además, incluye un subagent **general** para búsquedas complejas y tareas de varios pasos.
Además, incluye un subagente **general** para búsquedas complejas y tareas de varios pasos.
Se usa internamente y se puede invocar con `@general` en los mensajes.
Más información sobre [agents](https://opencode.ai/docs/agents).
Más información sobre [agentes](https://opencode.ai/docs/agents).
### Documentación
@@ -120,21 +120,9 @@ Para más información sobre cómo configurar OpenCode, [**ve a nuestra document
Si te interesa contribuir a OpenCode, lee nuestras [docs de contribución](./CONTRIBUTING.md) antes de enviar un pull request.
### Construyendo sobre OpenCode
### Proyectos basados en OpenCode
Si estás trabajando en un proyecto relacionado con OpenCode y usas "opencode" como parte del nombre; por ejemplo, "opencode-dashboard" u "opencode-mobile", agrega una nota en tu README para aclarar que no está construido por el equipo de OpenCode y que no está afiliado con nosotros de ninguna manera.
### FAQ
#### ¿En qué se diferencia de Claude Code?
Es muy similar a Claude Code en cuanto a capacidades. Estas son las diferencias clave:
- 100% open source
- No está acoplado a ningún proveedor. Aunque recomendamos los modelos que ofrecemos a través de [OpenCode Zen](https://opencode.ai/zen); OpenCode se puede usar con Claude, OpenAI, Google o incluso modelos locales. A medida que evolucionan los modelos, las brechas se cerrarán y los precios bajarán, por lo que ser agnóstico al proveedor es importante.
- Soporte LSP listo para usar
- Un enfoque en la TUI. OpenCode está construido por usuarios de neovim y los creadores de [terminal.shop](https://terminal.shop); vamos a empujar los límites de lo que es posible en la terminal.
- Arquitectura cliente/servidor. Esto, por ejemplo, permite ejecutar OpenCode en tu computadora mientras lo controlas de forma remota desde una app móvil. Esto significa que el frontend TUI es solo uno de los posibles clientes.
Si estás trabajando en un proyecto basado en OpenCode y usas "opencode" como parte del nombre, por ejemplo, "opencode-dashboard" u "opencode-mobile", agrega una nota en tu README para aclarar que no está hecho por el equipo de OpenCode y que no está afiliado con nosotros de ninguna manera.
---
-12
View File
@@ -124,18 +124,6 @@ Si vous souhaitez contribuer à OpenCode, lisez nos [docs de contribution](./CON
Si vous travaillez sur un projet lié à OpenCode et que vous utilisez "opencode" dans le nom du projet (par exemple, "opencode-dashboard" ou "opencode-mobile"), ajoutez une note dans votre README pour préciser qu'il n'est pas construit par l'équipe OpenCode et qu'il n'est pas affilié à nous.
### FAQ
#### En quoi est-ce différent de Claude Code ?
C'est très similaire à Claude Code en termes de capacités. Voici les principales différences :
- 100% open source
- Pas couplé à un fournisseur. Nous recommandons les modèles proposés via [OpenCode Zen](https://opencode.ai/zen) ; OpenCode peut être utilisé avec Claude, OpenAI, Google ou même des modèles locaux. Au fur et à mesure que les modèles évoluent, les écarts se réduiront et les prix baisseront, donc être agnostique au fournisseur est important.
- Support LSP prêt à l'emploi
- Un focus sur la TUI. OpenCode est construit par des utilisateurs de neovim et les créateurs de [terminal.shop](https://terminal.shop) ; nous allons repousser les limites de ce qui est possible dans le terminal.
- Architecture client/serveur. Cela permet par exemple de faire tourner OpenCode sur votre ordinateur tout en le pilotant à distance depuis une application mobile. Cela signifie que la TUI n'est qu'un des clients possibles.
---
**Rejoignez notre communauté** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash
Εάν εργάζεσαι σε ένα έργο σχετικό με το OpenCode και χρησιμοποιείτε το "opencode" ως μέρος του ονόματός του, για παράδειγμα "opencode-dashboard" ή "opencode-mobile", πρόσθεσε μια σημείωση στο README σας για να διευκρινίσεις ότι δεν είναι κατασκευασμένο από την ομάδα του OpenCode και δεν έχει καμία σχέση με εμάς.
### Συχνές Ερωτήσεις
#### Πώς διαφέρει αυτό από το Claude Code;
Είναι πολύ παρόμοιο με το Claude Code ως προς τις δυνατότητες. Ακολουθούν οι βασικές διαφορές:
- 100% ανοιχτού κώδικα
- Δεν είναι συνδεδεμένο με κανέναν πάροχο. Αν και συνιστούμε τα μοντέλα που παρέχουμε μέσω του [OpenCode Zen](https://opencode.ai/zen), το OpenCode μπορεί να χρησιμοποιηθεί με Claude, OpenAI, Google, ή ακόμα και τοπικά μοντέλα. Καθώς τα μοντέλα εξελίσσονται, τα κενά μεταξύ τους θα κλείσουν και οι τιμές θα μειωθούν, οπότε είναι σημαντικό να είσαι ανεξάρτητος από τον πάροχο.
- Out-of-the-box υποστήριξη LSP
- Εστίαση στο TUI. Το OpenCode είναι κατασκευασμένο από χρήστες που χρησιμοποιούν neovim και τους δημιουργούς του [terminal.shop](https://terminal.shop)· θα εξαντλήσουμε τα όρια του τι είναι δυνατό στο terminal.
- Αρχιτεκτονική client/server. Αυτό, για παράδειγμα, μπορεί να επιτρέψει στο OpenCode να τρέχει στον υπολογιστή σου ενώ το χειρίζεσαι εξ αποστάσεως από μια εφαρμογή κινητού, που σημαίνει ότι το TUI frontend είναι μόνο ένας από τους πιθανούς clients.
---
**Γίνε μέλος της κοινότητάς μας** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ Se sei interessato a contribuire a OpenCode, leggi la nostra [guida alla contrib
Se stai lavorando a un progetto correlato a OpenCode e che utilizza “opencode” come parte del nome (ad esempio “opencode-dashboard” o “opencode-mobile”), aggiungi una nota nel tuo README per chiarire che non è sviluppato dal team OpenCode e che non è affiliato in alcun modo con noi.
### FAQ
#### In cosa è diverso da Claude Code?
È molto simile a Claude Code in termini di funzionalità. Ecco le principali differenze:
- 100% open source
- Non è legato a nessun provider. Anche se consigliamo i modelli forniti tramite [OpenCode Zen](https://opencode.ai/zen), OpenCode può essere utilizzato con Claude, OpenAI, Google o persino modelli locali. Con levoluzione dei modelli, le differenze tra di essi si ridurranno e i prezzi scenderanno, quindi essere indipendenti dal provider è importante.
- Supporto LSP pronto alluso
- Forte attenzione alla TUI. OpenCode è sviluppato da utenti neovim e dai creatori di [terminal.shop](https://terminal.shop); spingeremo al limite ciò che è possibile fare nel terminale.
- Architettura client/server. Questo, ad esempio, permette a OpenCode di girare sul tuo computer mentre lo controlli da remoto tramite unapp mobile. La frontend TUI è quindi solo uno dei possibili client.
---
**Unisciti alla nostra community** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ OpenCode に貢献したい場合は、Pull Request を送る前に [contributin
OpenCode に関連するプロジェクトで、名前に "opencode"(例: "opencode-dashboard" や "opencode-mobile")を含める場合は、そのプロジェクトが OpenCode チームによって作られたものではなく、いかなる形でも関係がないことを README に明記してください。
### FAQ
#### Claude Code との違いは?
機能面では Claude Code と非常に似ています。主な違いは次のとおりです。
- 100% オープンソース
- 特定のプロバイダーに依存しません。[OpenCode Zen](https://opencode.ai/zen) で提供しているモデルを推奨しますが、OpenCode は Claude、OpenAI、Google、またはローカルモデルでも利用できます。モデルが進化すると差は縮まり価格も下がるため、provider-agnostic であることが重要です。
- そのまま使える LSP サポート
- TUI にフォーカス。OpenCode は neovim ユーザーと [terminal.shop](https://terminal.shop) の制作者によって作られており、ターミナルで可能なことの限界を押し広げます。
- クライアント/サーバー構成。例えば OpenCode をあなたのPCで動かし、モバイルアプリからリモート操作できます。TUI フロントエンドは複数あるクライアントの1つにすぎません。
---
**コミュニティに参加** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ OpenCode 에 기여하고 싶다면, Pull Request 를 제출하기 전에 [contr
OpenCode 와 관련된 프로젝트를 진행하면서 이름에 "opencode"(예: "opencode-dashboard" 또는 "opencode-mobile") 를 포함한다면, README 에 해당 프로젝트가 OpenCode 팀이 만든 것이 아니며 어떤 방식으로도 우리와 제휴되어 있지 않다는 점을 명시해 주세요.
### FAQ
#### Claude Code 와는 무엇이 다른가요?
기능 면에서는 Claude Code 와 매우 유사합니다. 주요 차이점은 다음과 같습니다.
- 100% 오픈 소스
- 특정 제공자에 묶여 있지 않습니다. [OpenCode Zen](https://opencode.ai/zen) 을 통해 제공하는 모델을 권장하지만, OpenCode 는 Claude, OpenAI, Google 또는 로컬 모델과도 사용할 수 있습니다. 모델이 발전하면서 격차는 줄고 가격은 내려가므로 provider-agnostic 인 것이 중요합니다.
- 기본으로 제공되는 LSP 지원
- TUI 에 집중. OpenCode 는 neovim 사용자와 [terminal.shop](https://terminal.shop) 제작자가 만들었으며, 터미널에서 가능한 것의 한계를 밀어붙입니다.
- 클라이언트/서버 아키텍처. 예를 들어 OpenCode 를 내 컴퓨터에서 실행하면서 모바일 앱으로 원격 조작할 수 있습니다. 즉, TUI 프런트엔드는 가능한 여러 클라이언트 중 하나일 뿐입니다.
---
**커뮤니티에 참여하기** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ If you're interested in contributing to OpenCode, please read our [contributing
If you are working on a project that's related to OpenCode and is using "opencode" as part of its name, for example "opencode-dashboard" or "opencode-mobile", please add a note to your README to clarify that it is not built by the OpenCode team and is not affiliated with us in any way.
### FAQ
#### How is this different from Claude Code?
It's very similar to Claude Code in terms of capability. Here are the key differences:
- 100% open source
- Not coupled to any provider. Although we recommend the models we provide through [OpenCode Zen](https://opencode.ai/zen), OpenCode can be used with Claude, OpenAI, Google, or even local models. As models evolve, the gaps between them will close and pricing will drop, so being provider-agnostic is important.
- Built-in opt-in LSP support
- A focus on TUI. OpenCode is built by neovim users and the creators of [terminal.shop](https://terminal.shop); we are going to push the limits of what's possible in the terminal.
- A client/server architecture. This, for example, can allow OpenCode to run on your computer while you drive it remotely from a mobile app, meaning that the TUI frontend is just one of the possible clients.
---
**Join our community** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ Hvis du vil bidra til OpenCode, les [contributing docs](./CONTRIBUTING.md) før
Hvis du jobber med et prosjekt som er relatert til OpenCode og bruker "opencode" som en del av navnet; for eksempel "opencode-dashboard" eller "opencode-mobile", legg inn en merknad i README som presiserer at det ikke er bygget av OpenCode-teamet og ikke er tilknyttet oss på noen måte.
### FAQ
#### Hvordan er dette forskjellig fra Claude Code?
Det er veldig likt Claude Code når det gjelder funksjonalitet. Her er de viktigste forskjellene:
- 100% open source
- Ikke knyttet til en bestemt leverandør. Selv om vi anbefaler modellene vi tilbyr gjennom [OpenCode Zen](https://opencode.ai/zen); kan OpenCode brukes med Claude, OpenAI, Google eller til og med lokale modeller. Etter hvert som modellene utvikler seg vil gapene lukkes og prisene gå ned, så det er viktig å være provider-agnostic.
- LSP-støtte rett ut av boksen
- Fokus på TUI. OpenCode er bygget av neovim-brukere og skaperne av [terminal.shop](https://terminal.shop); vi kommer til å presse grensene for hva som er mulig i terminalen.
- Klient/server-arkitektur. Dette kan for eksempel la OpenCode kjøre på maskinen din, mens du styrer den eksternt fra en mobilapp. Det betyr at TUI-frontend'en bare er en av de mulige klientene.
---
**Bli med i fellesskapet** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ Jeśli chcesz współtworzyć OpenCode, przeczytaj [contributing docs](./CONTRIB
Jeśli pracujesz nad projektem związanym z OpenCode i używasz "opencode" jako części nazwy (na przykład "opencode-dashboard" lub "opencode-mobile"), dodaj proszę notatkę do swojego README, aby wyjaśnić, że projekt nie jest tworzony przez zespół OpenCode i nie jest z nami w żaden sposób powiązany.
### FAQ
#### Czym to się różni od Claude Code?
Jest bardzo podobne do Claude Code pod względem możliwości. Oto kluczowe różnice:
- 100% open source
- Niezależne od dostawcy. Chociaż polecamy modele oferowane przez [OpenCode Zen](https://opencode.ai/zen); OpenCode może być używany z Claude, OpenAI, Google, a nawet z modelami lokalnymi. W miarę jak modele ewoluują, różnice będą się zmniejszać, a ceny spadać, więc ważna jest niezależność od dostawcy.
- Wbudowane wsparcie LSP
- Skupienie na TUI. OpenCode jest budowany przez użytkowników neovim i twórców [terminal.shop](https://terminal.shop); przesuwamy granice tego, co jest możliwe w terminalu.
- Architektura klient/serwer. Pozwala np. uruchomić OpenCode na twoim komputerze, a sterować nim zdalnie z aplikacji mobilnej. To znaczy, że frontend TUI jest tylko jednym z możliwych klientów.
---
**Dołącz do naszej społeczności** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash
Если вы делаете проект, связанный с OpenCode, и используете "opencode" как часть имени (например, "opencode-dashboard" или "opencode-mobile"), добавьте примечание в README, чтобы уточнить, что проект не создан командой OpenCode и не аффилирован с нами.
### FAQ
#### Чем это отличается от Claude Code?
По возможностям это очень похоже на Claude Code. Вот ключевые отличия:
- 100% open source
- Не привязано к одному провайдеру. Мы рекомендуем модели из [OpenCode Zen](https://opencode.ai/zen); но OpenCode можно использовать с Claude, OpenAI, Google или даже локальными моделями. По мере развития моделей разрыв будет сокращаться, а цены падать, поэтому важна независимость от провайдера.
- Поддержка LSP из коробки
- Фокус на TUI. OpenCode построен пользователями neovim и создателями [terminal.shop](https://terminal.shop); мы будем раздвигать границы того, что возможно в терминале.
- Архитектура клиент/сервер. Например, это позволяет запускать OpenCode на вашем компьютере, а управлять им удаленно из мобильного приложения. Это значит, что TUI-фронтенд - лишь один из возможных клиентов.
---
**Присоединяйтесь к нашему сообществу** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ OpenCode รวมเอเจนต์ในตัวสองตัวที
หากคุณทำงานในโปรเจกต์ที่เกี่ยวข้องกับ OpenCode และใช้ "opencode" เป็นส่วนหนึ่งของชื่อ เช่น "opencode-dashboard" หรือ "opencode-mobile" โปรดเพิ่มหมายเหตุใน README ของคุณเพื่อชี้แจงว่าไม่ได้สร้างโดยทีม OpenCode และไม่ได้เกี่ยวข้องกับเราในทางใด
### คำถามที่พบบ่อย
#### ต่างจาก Claude Code อย่างไร?
คล้ายกับ Claude Code มากในแง่ความสามารถ นี่คือความแตกต่างหลัก:
- โอเพนซอร์ส 100%
- ไม่ผูกมัดกับผู้ให้บริการใดๆ แม้ว่าเราจะแนะนำโมเดลที่เราจัดหาให้ผ่าน [OpenCode Zen](https://opencode.ai/zen) OpenCode สามารถใช้กับ Claude, OpenAI, Google หรือแม้กระทั่งโมเดลในเครื่องได้ เมื่อโมเดลพัฒนาช่องว่างระหว่างพวกมันจะปิดลงและราคาจะลดลง ดังนั้นการไม่ผูกมัดกับผู้ให้บริการจึงสำคัญ
- รองรับ LSP ใช้งานได้ทันทีหลังการติดตั้งโดยไม่ต้องปรับแต่งหรือเปลี่ยนแปลงฟังก์ชันการทำงานใด ๆ
- เน้นที่ TUI OpenCode สร้างโดยผู้ใช้ neovim และผู้สร้าง [terminal.shop](https://terminal.shop) เราจะผลักดันขีดจำกัดของสิ่งที่เป็นไปได้ในเทอร์มินัล
- สถาปัตยกรรมไคลเอนต์/เซิร์ฟเวอร์ ตัวอย่างเช่น อาจอนุญาตให้ OpenCode ทำงานบนคอมพิวเตอร์ของคุณ ในขณะที่คุณสามารถขับเคลื่อนจากระยะไกลผ่านแอปมือถือ หมายความว่า TUI frontend เป็นหนึ่งในไคลเอนต์ที่เป็นไปได้เท่านั้น
---
**ร่วมชุมชนของเรา** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ OpenCode'a katkıda bulunmak istiyorsanız, lütfen bir pull request göndermede
OpenCode ile ilgili bir proje üzerinde çalışıyorsanız ve projenizin adının bir parçası olarak "opencode" kullanıyorsanız (örneğin, "opencode-dashboard" veya "opencode-mobile"), lütfen README dosyanıza projenin OpenCode ekibi tarafından geliştirilmediğini ve bizimle hiçbir şekilde bağlantılı olmadığını belirten bir not ekleyin.
### SSS
#### Bu Claude Code'dan nasıl farklı?
Yetenekler açısından Claude Code'a çok benzer. İşte temel farklar:
- %100 açık kaynak
- Herhangi bir sağlayıcıya bağlı değil. [OpenCode Zen](https://opencode.ai/zen) üzerinden sunduğumuz modelleri önermekle birlikte; OpenCode, Claude, OpenAI, Google veya hatta yerel modellerle kullanılabilir. Modeller geliştikçe aralarındaki farklar kapanacak ve fiyatlar düşecek, bu nedenle sağlayıcıdan bağımsız olmak önemlidir.
- Kurulum gerektirmeyen hazır LSP desteği
- TUI odaklı yaklaşım. OpenCode, neovim kullanıcıları ve [terminal.shop](https://terminal.shop)'un geliştiricileri tarafından geliştirilmektedir; terminalde olabileceklerin sınırlarını zorlayacağız.
- İstemci/sunucu (client/server) mimarisi. Bu, örneğin OpenCode'un bilgisayarınızda çalışması ve siz onu bir mobil uygulamadan uzaktan yönetmenizi sağlar. TUI arayüzü olası istemcilerden sadece biridir.
---
**Topluluğumuza katılın** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -125,18 +125,6 @@ OpenCode містить два вбудовані агенти, між яким
Якщо ви працюєте над проєктом, пов'язаним з OpenCode, і використовуєте "opencode" у назві, наприклад "opencode-dashboard" або "opencode-mobile", додайте примітку до свого README.
Уточніть, що цей проєкт не створений командою OpenCode і жодним чином не афілійований із нами.
### FAQ
#### Чим це відрізняється від Claude Code?
За можливостями це дуже схоже на Claude Code. Ось ключові відмінності:
- 100% open source
- Немає прив'язки до конкретного провайдера. Ми рекомендуємо моделі, які надаємо через [OpenCode Zen](https://opencode.ai/zen), але OpenCode також працює з Claude, OpenAI, Google і навіть локальними моделями. З розвитком моделей різниця між ними зменшуватиметься, а ціни падатимуть, тому незалежність від провайдера має значення.
- Підтримка LSP з коробки
- Фокус на TUI. OpenCode створено користувачами neovim та авторами [terminal.shop](https://terminal.shop); ми й надалі розширюватимемо межі можливого в терміналі.
- Клієнт-серверна архітектура. Наприклад, це дає змогу запускати OpenCode на вашому комп'ютері й керувати ним віддалено з мобільного застосунку, тобто TUI-фронтенд - лише один із можливих клієнтів.
---
**Приєднуйтеся до нашої спільноти** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -124,18 +124,6 @@ Nếu bạn muốn đóng góp cho OpenCode, vui lòng đọc [tài liệu hư
Nếu bạn đang làm việc trên một dự án liên quan đến OpenCode và sử dụng "opencode" như một phần của tên dự án, ví dụ "opencode-dashboard" hoặc "opencode-mobile", vui lòng thêm một ghi chú vào README của bạn để làm rõ rằng dự án đó không được xây dựng bởi đội ngũ OpenCode và không liên kết với chúng tôi dưới bất kỳ hình thức nào.
### Các câu hỏi thường gặp (FAQ)
#### OpenCode khác biệt thế nào so với Claude Code?
Về mặt tính năng, nó rất giống Claude Code. Dưới đây là những điểm khác biệt chính:
- 100% mã nguồn mở
- Không bị ràng buộc với bất kỳ nhà cung cấp nào. Mặc dù chúng tôi khuyên dùng các mô hình được cung cấp qua [OpenCode Zen](https://opencode.ai/zen), OpenCode có thể được sử dụng với Claude, OpenAI, Google, hoặc thậm chí các mô hình chạy cục bộ. Khi các mô hình phát triển, khoảng cách giữa chúng sẽ thu hẹp lại và giá cả sẽ giảm, vì vậy việc không phụ thuộc vào nhà cung cấp là rất quan trọng.
- Hỗ trợ LSP ngay từ đầu
- Tập trung vào TUI (Giao diện người dùng dòng lệnh). OpenCode được xây dựng bởi những người dùng neovim và đội ngũ tạo ra [terminal.shop](https://terminal.shop); chúng tôi sẽ đẩy giới hạn của những gì có thể làm được trên terminal lên mức tối đa.
- Kiến trúc client/server. Chẳng hạn, điều này cho phép OpenCode chạy trên máy tính của bạn trong khi bạn điều khiển nó từ xa qua một ứng dụng di động, nghĩa là frontend TUI chỉ là một trong những client có thể dùng.
---
**Tham gia cộng đồng của chúng tôi** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
-12
View File
@@ -123,18 +123,6 @@ OpenCode 内置两种 Agent,可用 `Tab` 键快速切换:
如果你在项目名中使用了 “opencode”(如 “opencode-dashboard” 或 “opencode-mobile”),请在 README 里注明该项目不是 OpenCode 团队官方开发,且不存在隶属关系。
### 常见问题 (FAQ)
#### 这和 Claude Code 有什么不同?
功能上很相似,关键差异:
- 100% 开源。
- 不绑定特定提供商。推荐使用 [OpenCode Zen](https://opencode.ai/zen) 的模型,但也可搭配 Claude、OpenAI、Google 甚至本地模型。模型迭代会缩小差异、降低成本,因此保持 provider-agnostic 很重要。
- 内置 LSP 支持。
- 聚焦终端界面 (TUI)。OpenCode 由 Neovim 爱好者和 [terminal.shop](https://terminal.shop) 的创建者打造,会持续探索终端的极限。
- 客户端/服务器架构。可在本机运行,同时用移动设备远程驱动。TUI 只是众多潜在客户端之一。
---
**加入我们的社区** [飞书](https://applink.feishu.cn/client/chat/chatter/add_by_link?link_token=738j8655-cd59-4633-a30a-1124e0096789&qr_code=true) | [X.com](https://x.com/opencode)
-12
View File
@@ -123,18 +123,6 @@ OpenCode 內建了兩種 Agent,您可以使用 `Tab` 鍵快速切換。
如果您正在開發與 OpenCode 相關的專案,並在名稱中使用了 "opencode"(例如 "opencode-dashboard" 或 "opencode-mobile"),請在您的 README 中加入聲明,說明該專案並非由 OpenCode 團隊開發,且與我們沒有任何隸屬關係。
### 常見問題 (FAQ)
#### 這跟 Claude Code 有什麼不同?
在功能面上與 Claude Code 非常相似。以下是關鍵差異:
- 100% 開源。
- 不綁定特定的服務提供商。雖然我們推薦使用透過 [OpenCode Zen](https://opencode.ai/zen) 提供的模型,但 OpenCode 也可搭配 Claude, OpenAI, Google 甚至本地模型使用。隨著模型不斷演進,彼此間的差距會縮小且價格會下降,因此具備「不限廠商 (provider-agnostic)」的特性至關重要。
- 內建 LSP (語言伺服器協定) 支援。
- 專注於終端機介面 (TUI)。OpenCode 由 Neovim 愛好者與 [terminal.shop](https://terminal.shop) 的創作者打造。我們將不斷挑戰終端機介面的極限。
- 客戶端/伺服器架構 (Client/Server Architecture)。這讓 OpenCode 能夠在您的電腦上運行的同時,由行動裝置進行遠端操控。這意味著 TUI 前端只是眾多可能的客戶端之一。
---
**加入我們的社群** [飞书](https://applink.feishu.cn/client/chat/chatter/add_by_link?link_token=738j8655-cd59-4633-a30a-1124e0096789&qr_code=true) | [X.com](https://x.com/opencode)
+86 -419
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -1,6 +1,8 @@
[install]
exact = true
# Only install newly resolved package versions published at least 3 days ago.
minimumReleaseAge = 259200
minimumReleaseAgeExcludes = ["@opentui/core", "@opentui/core-darwin-arm64", "@opentui/core-darwin-x64", "@opentui/core-linux-arm64", "@opentui/core-linux-x64", "@opentui/core-win32-arm64", "@opentui/core-win32-x64", "@opentui/keymap", "@opentui/solid"]
[test]
root = "./do-not-run-tests-from-root"
+7 -10
View File
@@ -37,16 +37,14 @@
node_modules = final.callPackage ./nix/node_modules.nix {
inherit rev;
};
in
rec {
opencode = final.callPackage ./nix/opencode.nix {
inherit node_modules;
};
desktop = final.callPackage ./nix/desktop.nix {
opencode-desktop = final.callPackage ./nix/desktop.nix {
inherit opencode;
};
in
{
inherit opencode;
opencode-desktop = desktop;
};
};
@@ -56,16 +54,15 @@
node_modules = pkgs.callPackage ./nix/node_modules.nix {
inherit rev;
};
in
rec {
default = opencode;
opencode = pkgs.callPackage ./nix/opencode.nix {
inherit node_modules;
};
desktop = pkgs.callPackage ./nix/desktop.nix {
opencode-desktop = pkgs.callPackage ./nix/desktop.nix {
inherit opencode;
};
in
{
default = opencode;
inherit opencode desktop;
# Updater derivation with fakeHash - build fails and reveals correct hash
node_modules_updater = node_modules.override {
hash = pkgs.lib.fakeHash;
+10 -3
View File
@@ -223,8 +223,6 @@ const STRIPE_WEBHOOK_SECRET = new sst.Linkable("STRIPE_WEBHOOK_SECRET", {
properties: { value: stripeWebhook.secret },
})
const gatewayKv = new sst.cloudflare.Kv("GatewayKv")
////////////////
// CONSOLE
////////////////
@@ -274,7 +272,6 @@ new sst.cloudflare.x.SolidStart("Console", {
new sst.Secret("CLOUDFLARE_API_TOKEN", process.env.CLOUDFLARE_API_TOKEN!),
]
: []),
gatewayKv,
],
environment: {
//VITE_DOCS_URL: web.url.apply((url) => url!),
@@ -293,3 +290,13 @@ new sst.cloudflare.x.SolidStart("Console", {
},
},
})
////////////////
// HELPERS
////////////////
export const stat = new sst.cloudflare.Worker("Stat", {
handler: "packages/console/function/src/stat.ts",
link: [database],
url: true,
})
+115 -37
View File
@@ -1,6 +1,8 @@
import { SECRET } from "./secret"
import { domain } from "./stage"
const description = "Managed by SST (Don't edit in Honeycomb UI)"
const webhookRecipient = new honeycomb.WebhookRecipient("DiscordAlerts", {
name: $app.stage === "production" ? "Discord Alerts" : `Discord Alerts (${$app.stage})`,
url: `https://${domain}/honeycomb/webhook`,
@@ -25,6 +27,16 @@ const webhookRecipient = new honeycomb.WebhookRecipient("DiscordAlerts", {
],
})
// Honeycomb can keep stale query-local calculated fields when the name is unchanged,
// so tie the field name to the expression while avoiding deploy-to-deploy churn.
// https://github.com/honeycombio/terraform-provider-honeycombio/issues/852
const calculatedField = (field: { name: string; expression: string }) => ({
...field,
name: `${field.name}_${(
Array.from(field.expression).reduce((result, char) => Math.imul(31, result) + char.charCodeAt(0), 0) >>> 0
).toString(36)}`,
})
const modelHttpErrorsQuery = (product: "go" | "zen") => {
const filters = [
{ column: "model", op: "exists" },
@@ -32,70 +44,117 @@ const modelHttpErrorsQuery = (product: "go" | "zen") => {
{ column: "user_agent", op: "contains", value: "opencode" },
{ column: "isGoTier", op: "=", value: product === "go" ? "true" : "false" },
]
const failedHttpStatus = calculatedField({
name: "is_failed_http_status",
expression: `
IF(
AND(
GTE($status, "400"),
NOT(EQUALS($status, "401")),
NOT(
AND(
EQUALS($status, "429"),
OR(
EQUALS($error.type, "GoUsageLimitError"),
EQUALS($error.type, "FreeUsageLimitError")
)
)
)
),
1,
0
)`,
})
return honeycomb.getQuerySpecificationOutput({
breakdowns: ["model"],
calculatedFields: [
{
name: "is_failed_http_status",
expression:
product === "go"
? `IF(AND(GTE($status, "400"), NOT(EQUALS($status, "401")), NOT(EQUALS($status, "429"))), 1, 0)`
: `IF(AND(GTE($status, "400"), NOT(EQUALS($status, "401"))), 1, 0)`,
},
],
calculatedFields: [failedHttpStatus],
calculations: [
{ op: "COUNT", name: "TOTAL", filterCombination: "AND", filters },
{ op: "SUM", name: "FAILED", column: "is_failed_http_status", filterCombination: "AND", filters },
{
op: "SUM",
name: "FAILED",
column: failedHttpStatus.name,
filterCombination: "AND",
filters,
},
],
formulas: [{ name: "ERROR", expression: "IF(GTE($TOTAL, 100), DIV($FAILED, $TOTAL), 0)" }],
formulas: [{ name: "ERROR", expression: "IF(GTE($TOTAL, 200), DIV($FAILED, $TOTAL), 0)" }],
timeRange: 900,
}).json
}
const providerHttpErrorsQuery = (product: "go" | "zen") => {
const providerHttpErrorsQuery = () => {
const filters = [
{ column: "provider", op: "exists" },
{ column: "user_agent", op: "contains", value: "opencode" },
{ column: "isGoTier", op: "=", value: product === "go" ? "true" : "false" },
]
const successHttpStatus = calculatedField({
name: "is_success_http_status",
expression: `IF(AND(GTE($status, "200"), LT($status, "400")), 1, 0)`,
})
const failedProviderHttpStatus = calculatedField({
name: "is_failed_provider_http_status",
expression: `IF(GT($llm.error.code, "400"), 1, 0)`,
})
return honeycomb.getQuerySpecificationOutput({
breakdowns: ["provider"],
calculatedFields: [
{
name: "is_success_http_status",
expression: `IF(AND(GTE($status, "200"), LT($status, "400")), 1, 0)`,
},
{
name: "is_failed_provider_http_status",
expression: `IF(GT($llm.error.code, "400"), 1, 0)`,
},
],
calculatedFields: [successHttpStatus, failedProviderHttpStatus],
calculations: [
{
op: "SUM",
name: "SUCCESS",
column: "is_success_http_status",
column: successHttpStatus.name,
filterCombination: "AND",
filters: [...filters, { column: "event_type", op: "=", value: "completions" }],
},
{
op: "SUM",
name: "FAILED",
column: "is_failed_provider_http_status",
column: failedProviderHttpStatus.name,
filterCombination: "AND",
filters: [...filters, { column: "event_type", op: "=", value: "llm.error" }],
filters: [
...filters,
{ column: "event_type", op: "=", value: "llm.error" },
{ column: "llm.error.code", op: "!=", value: "404" },
],
},
],
formulas: [
{ name: "ERROR", expression: "IF(GTE(SUM($SUCCESS, $FAILED), 50), DIV($FAILED, SUM($SUCCESS, $FAILED)), 0)" },
{ name: "ERROR", expression: "IF(GTE(SUM($SUCCESS, $FAILED), 200), DIV($FAILED, SUM($SUCCESS, $FAILED)), 0)" },
],
timeRange: 900,
}).json
}
const description = "Managed by SST (Don't edit in Honeycomb UI)"
const modelLowTpsQuery = (product: "go" | "zen") => {
const filters = [
{ column: "model", op: "exists" },
{ column: "event_type", op: "=", value: "completions" },
{ column: "user_agent", op: "contains", value: "opencode" },
{ column: "isGoTier", op: "=", value: product === "go" ? "true" : "false" },
{ column: "status", op: ">=", value: "200" },
{ column: "status", op: "<", value: "400" },
{ column: "tps.output", op: "exists" },
]
return honeycomb.getQuerySpecificationOutput({
breakdowns: ["model"],
calculations: [
{ op: "COUNT", name: "TOTAL", filterCombination: "AND", filters },
{
op: "P50",
name: "TPS",
column: "tps.output",
filterCombination: "AND",
filters,
},
],
formulas: [{ name: "LOW_TPS", expression: "IF(GTE($TOTAL, 100), $TPS, 999)" }],
timeRange: 1800,
}).json
}
new honeycomb.Trigger("IncreasedModelHttpErrorsGo", {
name: "Increased Model HTTP Errors [Go]",
@@ -135,29 +194,48 @@ new honeycomb.Trigger("IncreasedModelHttpErrorsZen", {
],
})
new honeycomb.Trigger("IncreasedProviderHttpErrorsGo", {
name: "Increased Provider HTTP Errors [Go]",
new honeycomb.Trigger("LowModelTpsGo", {
name: "Low Model TPS [Go]",
description,
queryJson: providerHttpErrorsQuery("go"),
queryJson: modelLowTpsQuery("go"),
alertType: "on_change",
frequency: 300,
thresholds: [{ op: ">=", value: 0.7, exceededLimit: 1 }],
frequency: 600,
thresholds: [{ op: "<=", value: 10, exceededLimit: 1 }],
recipients: [
{
id: webhookRecipient.id,
notificationDetails: [
{
variables: [{ name: "type", value: "provider_http_errors" }],
variables: [{ name: "type", value: "model_low_tps" }],
},
],
},
],
})
new honeycomb.Trigger("IncreasedProviderHttpErrorsZen", {
name: "Increased Provider HTTP Errors [Zen]",
new honeycomb.Trigger("LowModelTpsZen", {
name: "Low Model TPS [Zen]",
description,
queryJson: providerHttpErrorsQuery("zen"),
queryJson: modelLowTpsQuery("zen"),
alertType: "on_change",
frequency: 600,
thresholds: [{ op: "<=", value: 10, exceededLimit: 1 }],
recipients: [
{
id: webhookRecipient.id,
notificationDetails: [
{
variables: [{ name: "type", value: "model_low_tps" }],
},
],
},
],
})
new honeycomb.Trigger("IncreasedProviderHttpErrors", {
name: "Increased Provider HTTP Errors",
description,
queryJson: providerHttpErrorsQuery(),
alertType: "on_change",
frequency: 300,
thresholds: [{ op: ">=", value: 0.7, exceededLimit: 1 }],
+74 -73
View File
@@ -1,100 +1,101 @@
{
lib,
stdenv,
rustPlatform,
pkg-config,
cargo-tauri,
bun,
nodejs,
cargo,
rustc,
jq,
wrapGAppsHook4,
electron_41,
makeWrapper,
dbus,
glib,
gtk4,
libsoup_3,
librsvg,
libappindicator,
glib-networking,
openssl,
webkitgtk_4_1,
gst_all_1,
writableTmpDirAsHomeHook,
autoPatchelfHook,
opencode,
}:
rustPlatform.buildRustPackage (finalAttrs: {
let
electron = electron_41;
in
stdenv.mkDerivation (finalAttrs: {
pname = "opencode-desktop";
inherit (opencode)
version
src
node_modules
patches
;
cargoRoot = "packages/desktop/src-tauri";
cargoLock.lockFile = ../packages/desktop/src-tauri/Cargo.lock;
buildAndTestSubdir = finalAttrs.cargoRoot;
inherit (opencode) version src node_modules;
nativeBuildInputs = [
pkg-config
cargo-tauri.hook
bun
nodejs # for patchShebangs node_modules
cargo
rustc
jq
nodejs
makeWrapper
] ++ lib.optionals stdenv.hostPlatform.isLinux [ wrapGAppsHook4 ];
buildInputs = lib.optionals stdenv.isLinux [
dbus
glib
gtk4
libsoup_3
librsvg
libappindicator
glib-networking
openssl
webkitgtk_4_1
gst_all_1.gstreamer
gst_all_1.gst-plugins-base
gst_all_1.gst-plugins-good
gst_all_1.gst-plugins-bad
writableTmpDirAsHomeHook
] ++ lib.optionals stdenv.hostPlatform.isLinux [
autoPatchelfHook
];
strictDeps = true;
buildInputs = lib.optionals stdenv.hostPlatform.isLinux [
(lib.getLib stdenv.cc.cc)
];
env = opencode.env // {
ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
};
# https://github.com/electron/electron/issues/31121
# mac builds use a .app bundle which doesnt have this issue
postPatch = lib.optionalString stdenv.isLinux ''
BASE_PATH=packages/desktop
FILES=(src/main/windows.ts)
for file in "''${FILES[@]}"; do
substituteInPlace $BASE_PATH/$file \
--replace-fail "process.resourcesPath" "'$out/opt/opencode-desktop/resources'"
done
'';
preBuild = ''
cp -a ${finalAttrs.node_modules}/{node_modules,packages} .
chmod -R u+w node_modules packages
cp -r "${electron.dist}" $HOME/.electron-dist
chmod -R u+w $HOME/.electron-dist
cp -R ${finalAttrs.node_modules}/. .
patchShebangs node_modules
patchShebangs packages/desktop/node_modules
mkdir -p packages/desktop/src-tauri/sidecars
cp ${opencode}/bin/opencode packages/desktop/src-tauri/sidecars/opencode-cli-${stdenv.hostPlatform.rust.rustcTarget}
patchShebangs packages/*/node_modules
'';
# see publish-tauri job in .github/workflows/publish.yml
tauriBuildFlags = [
"--config"
"tauri.prod.conf.json"
"--no-sign" # no code signing or auto updates
buildPhase = ''
runHook preBuild
cd packages/desktop
bun run build
npx electron-builder --dir \
--config electron-builder.config.ts \
--config.mac.identity=null \
--config.electronDist="$HOME/.electron-dist"
runHook postBuild
'';
installPhase =
''
runHook preInstall
''
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
mkdir -p $out/Applications
mv dist/mac*/*.app $out/Applications
makeWrapper "$out/Applications/OpenCode.app/Contents/MacOS/OpenCode" $out/bin/opencode-desktop
''
+ lib.optionalString stdenv.hostPlatform.isLinux ''
mkdir -p $out/opt/opencode-desktop
cp -r dist/linux*-unpacked/{resources,LICENSE*} $out/opt/opencode-desktop
makeWrapper ${lib.getExe electron} $out/bin/opencode-desktop \
--inherit-argv0 \
--set ELECTRON_FORCE_IS_PACKAGED 1 \
--add-flags $out/opt/opencode-desktop/resources/app.asar \
--add-flags "\''${NIXOS_OZONE_WL:+\''${WAYLAND_DISPLAY:+--ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime=true}}"
''
+ ''
runHook postInstall
'';
autoPatchelfIgnoreMissingDeps = [
"libc.musl-x86_64.so.1"
];
# FIXME: workaround for concerns about case insensitive filesystems
# should be removed once binary is renamed or decided otherwise
# darwin output is a .app bundle so no conflict
postFixup = lib.optionalString stdenv.hostPlatform.isLinux ''
mv $out/bin/OpenCode $out/bin/opencode-desktop
sed -i 's|^Exec=OpenCode$|Exec=opencode-desktop|' $out/share/applications/OpenCode.desktop
'';
meta = {
description = "OpenCode Desktop App";
homepage = "https://opencode.ai";
license = lib.licenses.mit;
mainProgram = "opencode-desktop";
inherit (opencode.meta) platforms;
inherit (opencode.meta) homepage license platforms;
};
})
+4 -4
View File
@@ -1,8 +1,8 @@
{
"nodeModules": {
"x86_64-linux": "sha256-LTo0ohJN5hBOubqFLVL45unVEIwBDkACNVv64k2nkq4=",
"aarch64-linux": "sha256-oYKY2UJRWG2fhufW4aGujX/Poou93023ZF2Fu7oyYOw=",
"aarch64-darwin": "sha256-618c9vqKN5I+no1nzylctAiWvqw7Bsa+bzSTNwXmSQA=",
"x86_64-darwin": "sha256-1ro3/gH0FC0TWXwWT+k675xR396GE98HpnBEeuD4t6k="
"x86_64-linux": "sha256-qAkjcbc1nJqOnCrNQ0bnsM4WG2ii5K1JWS9ohAYdjus=",
"aarch64-linux": "sha256-Nb+F0e3CvQv+uLzHzj9JKp5hV78mCnlSqFXzgIvgR24=",
"aarch64-darwin": "sha256-BIXALWWrjEZLUKZrY6l6+scjZmKFscFxX26TvWOvXGQ=",
"x86_64-darwin": "sha256-3uaFXl/n6je7AzIfsY1pvt3Ln/U1Oshx3z7ohuVPEs8="
}
}
+3 -2
View File
@@ -40,7 +40,7 @@ stdenvNoCC.mkDerivation (finalAttrs: {
env.MODELS_DEV_API_JSON = "${models-dev}/dist/_api.json";
env.OPENCODE_DISABLE_MODELS_FETCH = true;
env.OPENCODE_VERSION = finalAttrs.version;
env.OPENCODE_CHANNEL = "local";
env.OPENCODE_CHANNEL = "prod";
buildPhase = ''
runHook preBuild
@@ -89,11 +89,12 @@ stdenvNoCC.mkDerivation (finalAttrs: {
passthru = {
jsonschema = "${placeholder "out"}/share/opencode/schema.json";
env = finalAttrs.env;
};
meta = {
description = "The open source coding agent";
homepage = "https://opencode.ai/";
homepage = "https://opencode.ai";
license = lib.licenses.mit;
mainProgram = "opencode";
inherit (node_modules.meta) platforms;
+13 -9
View File
@@ -4,7 +4,7 @@
"description": "AI-powered development tool",
"private": true,
"type": "module",
"packageManager": "bun@1.3.13",
"packageManager": "bun@1.3.14",
"scripts": {
"dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts",
"dev:desktop": "bun --cwd packages/desktop dev",
@@ -28,16 +28,16 @@
"packages/slack"
],
"catalog": {
"@effect/opentelemetry": "4.0.0-beta.57",
"@effect/platform-node": "4.0.0-beta.57",
"@effect/opentelemetry": "4.0.0-beta.65",
"@effect/platform-node": "4.0.0-beta.65",
"@npmcli/arborist": "9.4.0",
"@types/bun": "1.3.12",
"@types/bun": "1.3.13",
"@types/cross-spawn": "6.0.6",
"@octokit/rest": "22.0.0",
"@hono/zod-validator": "0.4.2",
"@opentui/core": "0.2.6",
"@opentui/keymap": "0.2.6",
"@opentui/solid": "0.2.6",
"@opentui/core": "0.2.14",
"@opentui/keymap": "0.2.14",
"@opentui/solid": "0.2.14",
"ulid": "3.0.1",
"@kobalte/core": "0.13.11",
"@types/luxon": "3.7.1",
@@ -55,7 +55,7 @@
"dompurify": "3.3.1",
"drizzle-kit": "1.0.0-beta.19-d95b7a4",
"drizzle-orm": "1.0.0-beta.19-d95b7a4",
"effect": "4.0.0-beta.59",
"effect": "4.0.0-beta.65",
"ai": "6.0.168",
"cross-spawn": "7.0.6",
"hono": "4.10.7",
@@ -74,7 +74,7 @@
"shiki": "3.20.0",
"solid-list": "0.3.0",
"tailwindcss": "4.1.11",
"virtua": "0.42.3",
"virtua": "0.49.1",
"vite": "7.1.4",
"@solidjs/meta": "0.29.4",
"@solidjs/router": "0.15.4",
@@ -128,11 +128,15 @@
"electron"
],
"overrides": {
"@opentui/core": "catalog:",
"@opentui/keymap": "catalog:",
"@opentui/solid": "catalog:",
"@types/bun": "catalog:",
"@types/node": "catalog:"
},
"patchedDependencies": {
"@npmcli/agent@4.0.0": "patches/@npmcli%2Fagent@4.0.0.patch",
"@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer%2Fphoton-node@0.3.4.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"
}
-1
View File
@@ -10,7 +10,6 @@
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-v3.png" />
<link rel="manifest" href="/site.webmanifest" />
<meta name="theme-color" content="#F8F7F7" />
<meta name="theme-color" content="#131010" media="(prefers-color-scheme: dark)" />
<meta property="og:image" content="/social-share.png" />
<meta property="twitter:image" content="/social-share.png" />
<script id="oc-theme-preload-script" src="/oc-theme-preload.js"></script>
+2 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/app",
"version": "1.14.43",
"version": "1.15.4",
"description": "",
"type": "module",
"exports": {
@@ -73,7 +73,6 @@
"solid-js": "catalog:",
"solid-list": "catalog:",
"tailwindcss": "catalog:",
"virtua": "catalog:",
"zod": "catalog:"
"virtua": "catalog:"
}
}
+4
View File
@@ -16,6 +16,10 @@
document.documentElement.dataset.theme = themeId
document.documentElement.dataset.colorScheme = mode
// Update theme-color meta tag to match app color scheme
var metas = document.querySelectorAll("meta[name='theme-color']")
if (metas.length > 0) metas[0].setAttribute("content", isDark ? "#131010" : "#F8F7F7")
if (themeId === "oc-2") return
var css = localStorage.getItem("opencode-theme-css-" + mode)
@@ -107,7 +107,8 @@ function createCommandEntries(props: {
const allowed = createMemo(() => {
if (props.filesOnly()) return []
return props.command.options.filter(
(option) => !option.disabled && !option.id.startsWith("suggested.") && option.id !== "file.open",
(option) =>
!option.disabled && !option.hidden && !option.id.startsWith("suggested.") && option.id !== "file.open",
)
})
@@ -6,12 +6,14 @@ import { Dialog } from "@opencode-ai/ui/dialog"
import { List } from "@opencode-ai/ui/list"
import { Switch } from "@opencode-ai/ui/switch"
import { useLanguage } from "@/context/language"
import { mcpQueryKey } from "@/context/global-sync"
import { useQueryOptions } from "@/context/global-sync"
import { pathKey } from "@/utils/path-key"
const statusLabels = {
connected: "mcp.status.connected",
failed: "mcp.status.failed",
needs_auth: "mcp.status.needs_auth",
needs_client_registration: "mcp.status.needs_client_registration",
disabled: "mcp.status.disabled",
} as const
@@ -20,6 +22,7 @@ export const DialogSelectMcp: Component = () => {
const sdk = useSDK()
const language = useLanguage()
const queryClient = useQueryClient()
const queryOptions = useQueryOptions()
const items = createMemo(() =>
Object.entries(sync.data.mcp ?? {})
@@ -29,10 +32,18 @@ export const DialogSelectMcp: Component = () => {
const toggle = useMutation(() => ({
mutationFn: async (name: string) => {
if (sync.data.mcp[name]?.status === "connected") await sdk.client.mcp.disconnect({ name })
else await sdk.client.mcp.connect({ name })
const status = sync.data.mcp[name]
if (status?.status === "connected") {
await sdk.client.mcp.disconnect({ name })
return
}
if (status?.status === "needs_auth") {
await sdk.client.mcp.auth.authenticate({ name })
return
}
await sdk.client.mcp.connect({ name })
},
onSuccess: () => queryClient.refetchQueries({ queryKey: mcpQueryKey(sync.directory) }),
onSuccess: () => queryClient.refetchQueries(queryOptions.mcp(pathKey(sync.directory))),
}))
const enabledCount = createMemo(() => items().filter((i) => i.status === "connected").length)
@@ -65,7 +76,7 @@ export const DialogSelectMcp: Component = () => {
}
const error = () => {
const s = mcpStatus()
return s?.status === "failed" ? s.error : undefined
if (s?.status === "failed" || s?.status === "needs_client_registration") return s.error
}
const enabled = () => status() === "connected"
return (
@@ -76,9 +87,6 @@ export const DialogSelectMcp: Component = () => {
<Show when={statusLabel()}>
<span class="text-11-regular text-text-weaker">{statusLabel()}</span>
</Show>
<Show when={toggle.isPending && toggle.variables === i.name}>
<span class="text-11-regular text-text-weak">{language.t("common.loading.ellipsis")}</span>
</Show>
</div>
<Show when={error()}>
<span class="text-11-regular text-text-weaker truncate">{error()}</span>
@@ -0,0 +1,44 @@
import { usePlatform } from "@/context/platform"
import { Button } from "@opencode-ai/ui/button"
import { useDialog } from "@opencode-ai/ui/context/dialog"
import { Dialog } from "@opencode-ai/ui/dialog"
import { JSX } from "solid-js"
export type DialogGoUpsellProps = {
title: string
description: JSX.Element
link?: string
actionLabel: string
onClose?: (dontShowAgain?: boolean) => void
}
export function DialogUsageExceeded(props: DialogGoUpsellProps) {
const dialog = useDialog()
const platform = usePlatform()
const runAction = () => {
if (props.link) platform.openLink(props.link)
props.onClose?.()
dialog.close()
}
const dismiss = () => {
props.onClose?.(true)
dialog.close()
}
return (
<Dialog title={props.title} description={props.description} fit>
<div class="flex flex-col gap-4 pl-6 pr-2.5 pb-3">
<div class="flex justify-end gap-2">
<Button variant="ghost" size="large" onClick={dismiss}>
Don't show again
</Button>
<Button variant="primary" size="large" onClick={runAction}>
{props.actionLabel}
</Button>
</div>
</div>
</Dialog>
)
}
+10 -16
View File
@@ -16,7 +16,6 @@ import {
} from "@/context/prompt"
import { useLayout } from "@/context/layout"
import { useSDK } from "@/context/sdk"
import { useGlobalSDK } from "@/context/global-sdk"
import { useSync } from "@/context/sync"
import { useComments } from "@/context/comments"
import { Button } from "@opencode-ai/ui/button"
@@ -56,7 +55,8 @@ import { PromptDragOverlay } from "./prompt-input/drag-overlay"
import { promptPlaceholder } from "./prompt-input/placeholder"
import { ImagePreview } from "@opencode-ai/ui/image-preview"
import { useQueries } from "@tanstack/solid-query"
import { loadAgentsQuery, loadProvidersQuery } from "@/context/global-sync/bootstrap"
import { useQueryOptions } from "@/context/global-sync"
import { pathKey } from "@/utils/path-key"
interface PromptInputProps {
class?: string
@@ -99,11 +99,9 @@ const EXAMPLES = [
"prompt.example.25",
] as const
const NON_EMPTY_TEXT = /[^\s\u200B]/
export const PromptInput: Component<PromptInputProps> = (props) => {
const sdk = useSDK()
const globalSDK = useGlobalSDK()
const queryOptions = useQueryOptions()
const sync = useSync()
const local = useLocal()
@@ -240,13 +238,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
return paths
})
const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined))
const status = createMemo(
() =>
sync.data.session_status[params.id ?? ""] ?? {
type: "idle",
},
)
const working = createMemo(() => status()?.type !== "idle")
const working = createMemo(() => sync.data.session_working(params.id ?? ""))
const imageAttachments = createMemo(() =>
prompt.current().filter((part): part is ImageAttachmentPart => part.type === "image"),
)
@@ -866,7 +858,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
? rawParts[0].content
: rawParts.map((p) => ("content" in p ? p.content : "")).join("")
const hasNonText = rawParts.some((part) => part.type !== "text")
const shouldReset = !NON_EMPTY_TEXT.test(rawText) && !hasNonText && images.length === 0
const textContent = (editorRef.textContent ?? "").replace(/\u200B/g, "")
const shouldReset =
textContent.length === 0 && rawText.replace(/\n/g, "").length === 0 && !hasNonText && images.length === 0
if (shouldReset) {
closePopover()
@@ -1256,9 +1250,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
const [agentsQuery, globalProvidersQuery, providersQuery] = useQueries(() => ({
queries: [
loadAgentsQuery(sdk.directory, sdk.client),
loadProvidersQuery(null, globalSDK.client),
loadProvidersQuery(sdk.directory, sdk.client),
queryOptions.agents(pathKey(sdk.directory)),
queryOptions.providers(null),
queryOptions.providers(pathKey(sdk.directory)),
],
}))
@@ -123,11 +123,13 @@ function listFor(command: CommandContext, map: KeybindMap, palette: string) {
for (const opt of command.catalog) {
if (opt.id.startsWith("suggested.")) continue
if (opt.hidden) continue
out.set(opt.id, { title: opt.title, group: groupFor(opt.id) })
}
for (const opt of command.options) {
if (opt.id.startsWith("suggested.")) continue
if (opt.hidden) continue
out.set(opt.id, { title: opt.title, group: groupFor(opt.id) })
}
@@ -15,7 +15,8 @@ import { useSDK } from "@/context/sdk"
import { normalizeServerUrl, ServerConnection, useServer } from "@/context/server"
import { useSync } from "@/context/sync"
import { useCheckServerHealth, type ServerHealth } from "@/utils/server-health"
import { mcpQueryKey } from "@/context/global-sync"
import { useQueryOptions } from "@/context/global-sync"
import { pathKey } from "@/utils/path-key"
const pollMs = 10_000
@@ -139,13 +140,22 @@ const useMcpToggleMutation = () => {
const sdk = useSDK()
const language = useLanguage()
const queryClient = useQueryClient()
const queryOptions = useQueryOptions()
return useMutation(() => ({
mutationFn: async (name: string) => {
const status = sync.data.mcp[name]
await (status?.status === "connected" ? sdk.client.mcp.disconnect({ name }) : sdk.client.mcp.connect({ name }))
if (status?.status === "connected") {
await sdk.client.mcp.disconnect({ name })
return
}
if (status?.status === "needs_auth") {
await sdk.client.mcp.auth.authenticate({ name })
return
}
await sdk.client.mcp.connect({ name })
},
onSuccess: () => queryClient.refetchQueries({ queryKey: mcpQueryKey(sync.directory) }),
onSuccess: () => queryClient.refetchQueries(queryOptions.mcp(pathKey(sync.directory))),
onError: (err) => {
showToast({
variant: "error",
@@ -314,7 +324,7 @@ export function StatusPopoverBody(props: { shown: Accessor<boolean> }) {
return (
<button
type="button"
class="flex items-center gap-2 w-full h-8 pl-3 pr-2 py-1 rounded-md hover:bg-surface-raised-base-hover transition-colors text-left"
class="flex items-center gap-2 w-full min-h-8 pl-3 pr-2 py-1 rounded-md hover:bg-surface-raised-base-hover transition-colors text-left"
onClick={() => {
if (toggleMcp.isPending) return
toggleMcp.mutate(name)
@@ -331,7 +341,16 @@ export function StatusPopoverBody(props: { shown: Accessor<boolean> }) {
status() === "needs_auth" || status() === "needs_client_registration",
}}
/>
<span class="text-14-regular text-text-base truncate flex-1">{name}</span>
<span class="flex flex-col min-w-0 flex-1">
<span class="flex items-center gap-2 min-w-0">
<span class="text-14-regular text-text-base truncate">{name}</span>
</span>
<Show when={status() === "needs_auth"}>
<span class="text-11-regular text-text-weaker truncate">
{language.t("mcp.auth.clickToAuthenticate")}
</span>
</Show>
</span>
<div onClick={(event) => event.stopPropagation()}>
<Switch
checked={enabled()}
@@ -14,12 +14,14 @@ export function StatusPopover() {
const sync = useSync()
const [shown, setShown] = createSignal(false)
const ready = createMemo(() => server.healthy() === false || sync.data.mcp_ready)
const healthy = createMemo(() => {
const serverHealthy = server.healthy() === true
const mcpIssue = createMemo(() => {
const mcp = Object.values(sync.data.mcp ?? {})
const issue = mcp.some((item) => item.status !== "connected" && item.status !== "disabled")
return serverHealthy && !issue
const failed = mcp.some((item) => item.status === "failed" || item.status === "needs_client_registration")
const warn = mcp.some((item) => item.status === "needs_auth")
if (failed) return "critical" as const
if (warn) return "warning" as const
})
const healthy = createMemo(() => server.healthy() === true && !mcpIssue())
return (
<Popover
@@ -41,7 +43,9 @@ export function StatusPopover() {
classList={{
"absolute -top-px -right-px size-1.5 rounded-full": true,
"bg-icon-success-base": ready() && healthy(),
"bg-icon-critical-base": server.healthy() === false || (ready() && !healthy()),
"bg-icon-warning-base": ready() && server.healthy() === true && mcpIssue() === "warning",
"bg-icon-critical-base":
server.healthy() === false || (ready() && server.healthy() === true && mcpIssue() === "critical"),
"bg-border-weak-base": server.healthy() === undefined || !ready(),
}}
/>
+10 -7
View File
@@ -81,6 +81,7 @@ export interface CommandOption {
slash?: string
suggested?: boolean
disabled?: boolean
hidden?: boolean
onSelect?: (source?: "palette" | "keybind" | "slash") => void
onHighlight?: () => (() => void) | void
}
@@ -93,6 +94,7 @@ export type CommandCatalogItem = {
category?: string
keybind?: KeybindConfig
slash?: string
hidden?: boolean
}
export type CommandRegistration = {
@@ -279,13 +281,14 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex
setCatalog(
registered().reduce((acc, opt) => {
const id = actionId(opt.id)
acc[id] = {
title: opt.title,
description: opt.description,
category: opt.category,
keybind: opt.keybind,
slash: opt.slash,
}
if (opt.title)
acc[id] = {
title: opt.title,
description: opt.description,
category: opt.category,
keybind: opt.keybind,
slash: opt.slash,
}
return acc
}, {} as CommandCatalog),
)
+3 -5
View File
@@ -3,15 +3,13 @@ import { createSimpleContext } from "@opencode-ai/ui/context"
import { createGlobalEmitter } from "@solid-primitives/event-bus"
import { makeEventListener } from "@solid-primitives/event-listener"
import { batch, onCleanup, onMount } from "solid-js"
import z from "zod"
import { createSdkForServer } from "@/utils/server"
import { useLanguage } from "./language"
import { usePlatform } from "./platform"
import { useServer } from "./server"
const abortError = z.object({
name: z.literal("AbortError"),
})
const isAbortError = (error: unknown) =>
error !== null && typeof error === "object" && "name" in error && error.name === "AbortError"
export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleContext({
name: "GlobalSDK",
@@ -103,7 +101,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
let streamErrorLogged = false
const wait = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms))
const aborted = (error: unknown) => abortError.safeParse(error).success
const aborted = isAbortError
let attempt: AbortController | undefined
let run: Promise<void> | undefined
+43 -28
View File
@@ -18,8 +18,10 @@ import {
bootstrapDirectory,
bootstrapGlobal,
clearProviderRev,
loadAgentsQuery,
loadGlobalConfigQuery,
loadPathQuery,
loadProjectsQuery,
loadProvidersQuery,
} from "./global-sync/bootstrap"
import { createChildStoreManager } from "./global-sync/child-store"
@@ -33,6 +35,7 @@ import { formatServerError } from "@/utils/server-errors"
import { queryOptions, useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/solid-query"
import { createRefreshQueue } from "./global-sync/queue"
import { directoryKey } from "./global-sync/utils"
import { PathKey } from "@/utils/path-key"
type GlobalStore = {
ready: boolean
@@ -48,24 +51,33 @@ type GlobalStore = {
reload: undefined | "pending" | "complete"
}
export const loadSessionsQueryKey = (directory: string) => [directory, "loadSessions"] as const
export const mcpQueryKey = (directory: string) => [directory, "mcp"] as const
export const loadMcpQuery = (directory: string, sdk: OpencodeClient) =>
queryOptions({
queryKey: mcpQueryKey(directory),
queryKey: [directory, "mcp"] as const,
queryFn: () => sdk.mcp.status().then((r) => r.data ?? {}),
})
export const lspQueryKey = (directory: string) => [directory, "lsp"] as const
export const loadLspQuery = (directory: string, sdk: OpencodeClient) =>
queryOptions({
queryKey: lspQueryKey(directory),
queryKey: [directory, "lsp"] as const,
queryFn: () => sdk.lsp.status().then((r) => r.data ?? []),
})
function makeQueryOptionsApi(globalSDK: () => OpencodeClient, sdkFor: (dir: PathKey) => OpencodeClient) {
return {
globalConfig: () => loadGlobalConfigQuery(globalSDK()),
projects: () => loadProjectsQuery(globalSDK()),
providers: (directory: PathKey | null) =>
loadProvidersQuery(directory, directory === null ? globalSDK() : sdkFor(directory)),
path: (directory: PathKey | null) => loadPathQuery(directory, directory === null ? globalSDK() : sdkFor(directory)),
agents: (directory: PathKey) => loadAgentsQuery(directory, sdkFor(directory)),
mcp: (directory: PathKey) => loadMcpQuery(directory, sdkFor(directory)),
lsp: (directory: PathKey) => loadLspQuery(directory, sdkFor(directory)),
sessions: (directory: PathKey) => ({ queryKey: [directory, "loadSessions"] as const }),
}
}
export type QueryOptionsApi = ReturnType<typeof makeQueryOptionsApi>
function createGlobalSync() {
const globalSDK = useGlobalSDK()
const language = useLanguage()
@@ -77,12 +89,22 @@ function createGlobalSync() {
const sessionLoads = new Map<string, Promise<void>>()
const sessionMeta = new Map<string, { limit: number }>()
const sdkFor = (directory: string) => {
const key = directoryKey(directory)
const cached = sdkCache.get(key)
if (cached) return cached
const sdk = globalSDK.createClient({
directory,
throwOnError: true,
})
sdkCache.set(key, sdk)
return sdk
}
const queryOptionsApi = makeQueryOptionsApi(() => globalSDK.client, sdkFor)
const [configQuery, providerQuery, pathQuery] = useQueries(() => ({
queries: [
loadGlobalConfigQuery(globalSDK.client),
loadProvidersQuery(null, globalSDK.client),
loadPathQuery(null, globalSDK.client),
],
queries: [queryOptionsApi.globalConfig(), queryOptionsApi.providers(null), queryOptionsApi.path(null)],
}))
const [globalStore, setGlobalStore] = createStore<GlobalStore>({
@@ -181,18 +203,6 @@ function createGlobalSync() {
bootstrapInstance,
})
const sdkFor = (directory: string) => {
const key = directoryKey(directory)
const cached = sdkCache.get(key)
if (cached) return cached
const sdk = globalSDK.createClient({
directory,
throwOnError: true,
})
sdkCache.set(key, sdk)
return sdk
}
const children = createChildStoreManager({
owner,
isBooting: (directory) => booting.has(directory),
@@ -209,7 +219,7 @@ function createGlobalSync() {
clearSessionPrefetchDirectory(key)
},
translate: language.t,
getSdk: sdkFor,
queryOptions: queryOptionsApi,
global: {
provider: globalStore.provider,
},
@@ -239,7 +249,7 @@ function createGlobalSync() {
const limit = Math.max(store.limit + SESSION_RECENT_LIMIT, SESSION_RECENT_LIMIT)
const promise = queryClient
.fetchQuery({
queryKey: loadSessionsQueryKey(key),
...queryOptionsApi.sessions(key),
queryFn: () =>
loadRootSessionsWithFallback({
directory,
@@ -368,7 +378,7 @@ function createGlobalSync() {
setSessionTodo,
vcsCache: children.vcsCache.get(key),
loadLsp: () => {
void queryClient.fetchQuery(loadLspQuery(key, sdkFor(directory)))
void queryClient.fetchQuery(queryOptionsApi.lsp(key))
},
})
})
@@ -426,6 +436,7 @@ function createGlobalSync() {
},
child: children.child,
peek: children.peek,
queryOptions: queryOptionsApi,
// bootstrap,
updateConfig: updateConfigMutation.mutateAsync,
project: projectApi,
@@ -447,3 +458,7 @@ export function useGlobalSync() {
if (!context) throw new Error("useGlobalSync must be used within GlobalSyncProvider")
return context
}
export function useQueryOptions() {
return useGlobalSync().queryOptions
}
@@ -22,7 +22,7 @@ describe("createChildStoreManager", () => {
onBootstrap() {},
onDispose() {},
translate: (key) => key,
getSdk: () => null!,
queryOptions: {} as any,
global: { provider: null! },
})
@@ -1,7 +1,7 @@
import { createRoot, getOwner, onCleanup, runWithOwner, type Owner } from "solid-js"
import { createStore, type SetStoreFunction, type Store } from "solid-js/store"
import { Persist, persisted } from "@/utils/persist"
import type { OpencodeClient, ProviderListResponse, VcsInfo } from "@opencode-ai/sdk/v2/client"
import type { ProviderListResponse, VcsInfo } from "@opencode-ai/sdk/v2/client"
import {
DIR_IDLE_TTL_MS,
MAX_DIR_STORES,
@@ -15,8 +15,7 @@ import {
} from "./types"
import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction"
import { useQueries } from "@tanstack/solid-query"
import { loadPathQuery, loadProvidersQuery } from "./bootstrap"
import { loadLspQuery, loadMcpQuery } from "../global-sync"
import { QueryOptionsApi } from "../global-sync"
import { directoryKey, type DirectoryKey } from "./utils"
export function createChildStoreManager(input: {
@@ -26,7 +25,7 @@ export function createChildStoreManager(input: {
onBootstrap: (directory: string) => void
onDispose: (directory: string) => void
translate: (key: string, vars?: Record<string, string | number>) => string
getSdk: (directory: string) => OpencodeClient
queryOptions: QueryOptionsApi
global: {
provider: ProviderListResponse
}
@@ -171,17 +170,15 @@ export function createChildStoreManager(input: {
const init = () =>
createRoot((dispose) => {
const sdk = input.getSdk(directory)
const initialMeta = meta[0].value
const initialIcon = icon[0].value
const [pathQuery, mcpQuery, lspQuery, providerQuery] = useQueries(() => ({
queries: [
loadPathQuery(key, sdk),
loadMcpQuery(key, sdk),
loadLspQuery(key, sdk),
loadProvidersQuery(key, sdk),
input.queryOptions.path(key),
input.queryOptions.mcp(key),
input.queryOptions.lsp(key),
input.queryOptions.providers(key),
],
}))
@@ -211,6 +208,10 @@ export function createChildStoreManager(input: {
session: [],
sessionTotal: 0,
session_status: {},
session_working(id: string) {
const type = this.session_status[id]?.type
return (type ?? "idle") !== "idle"
},
session_diff: {},
todo: {},
permission: {},
@@ -231,6 +232,7 @@ export function createChildStoreManager(input: {
limit: 5,
message: {},
part: {},
part_text_accum_delta: {},
})
children[key] = child
disposers.set(key, dispose)
@@ -81,6 +81,7 @@ const baseState = (input: Partial<State> = {}) =>
limit: 10,
message: {},
part: {},
part_text_accum_delta: {},
...input,
}) as State
@@ -125,6 +125,7 @@ export function applyDirectoryEvent(input: {
const info = (event.properties as { info: Session }).info
const result = Binary.search(input.store.session, info.id, (s) => s.id)
if (info.time.archived) {
if (input.store.session[result.index]!.time.archived === info.time.archived) break
if (result.found) {
input.setStore(
"session",
@@ -211,6 +212,12 @@ export function applyDirectoryEvent(input: {
const result = Binary.search(messages, props.messageID, (m) => m.id)
if (result.found) messages.splice(result.index, 1)
}
const parts = draft.part[props.messageID]
if (parts) {
for (const part of parts) {
delete draft.part_text_accum_delta[part.id]
}
}
delete draft.part[props.messageID]
}),
)
@@ -219,6 +226,11 @@ export function applyDirectoryEvent(input: {
case "message.part.updated": {
const part = (event.properties as { part: Part }).part
if (SKIP_PARTS.has(part.type)) break
input.setStore(
produce((draft) => {
delete draft.part_text_accum_delta[part.id]
}),
)
const parts = input.store.part[part.messageID]
if (!parts) {
input.setStore("part", part.messageID, [part])
@@ -240,6 +252,11 @@ export function applyDirectoryEvent(input: {
}
case "message.part.removed": {
const props = event.properties as { messageID: string; partID: string }
input.setStore(
produce((draft) => {
delete draft.part_text_accum_delta[props.partID]
}),
)
const parts = input.store.part[props.messageID]
if (!parts) break
const result = Binary.search(parts, props.partID, (p) => p.id)
@@ -263,6 +280,7 @@ export function applyDirectoryEvent(input: {
if (!parts) break
const result = Binary.search(parts, props.partID, (p) => p.id)
if (!result.found) break
input.setStore("part_text_accum_delta", props.partID, (existing) => (existing ?? "") + props.delta)
input.setStore(
"part",
props.messageID,
@@ -39,6 +39,7 @@ describe("app session cache", () => {
part: Record<string, Part[] | undefined>
permission: Record<string, PermissionRequest[] | undefined>
question: Record<string, QuestionRequest[] | undefined>
part_text_accum_delta: Record<string, string | undefined>
} = {
session_status: { ses_1: { type: "busy" } as SessionStatus },
session_diff: { ses_1: [] },
@@ -47,12 +48,14 @@ describe("app session cache", () => {
part: { msg_1: [part("prt_1", "ses_1", "msg_1")] },
permission: { ses_1: [] as PermissionRequest[] },
question: { ses_1: [] as QuestionRequest[] },
part_text_accum_delta: { prt_1: "streamed text" },
}
dropSessionCaches(store, ["ses_1"])
expect(store.message.ses_1).toBeUndefined()
expect(store.part.msg_1).toBeUndefined()
expect(store.part_text_accum_delta.prt_1).toBeUndefined()
expect(store.todo.ses_1).toBeUndefined()
expect(store.session_diff.ses_1).toBeUndefined()
expect(store.session_status.ses_1).toBeUndefined()
@@ -70,6 +73,7 @@ describe("app session cache", () => {
part: Record<string, Part[] | undefined>
permission: Record<string, PermissionRequest[] | undefined>
question: Record<string, QuestionRequest[] | undefined>
part_text_accum_delta: Record<string, string | undefined>
} = {
session_status: {},
session_diff: {},
@@ -78,6 +82,7 @@ describe("app session cache", () => {
part: { [m.id]: [part("prt_1", "ses_1", m.id)] },
permission: {},
question: {},
part_text_accum_delta: {},
}
dropSessionCaches(store, ["ses_1"])
@@ -18,6 +18,7 @@ type SessionCache = {
part: Record<string, Part[] | undefined>
permission: Record<string, PermissionRequest[] | undefined>
question: Record<string, QuestionRequest[] | undefined>
part_text_accum_delta: Record<string, string | undefined>
}
export function dropSessionCaches(store: SessionCache, sessionIDs: Iterable<string>) {
@@ -27,6 +28,9 @@ export function dropSessionCaches(store: SessionCache, sessionIDs: Iterable<stri
for (const key of Object.keys(store.part)) {
const parts = store.part[key]
if (!parts?.some((part) => stale.has(part?.sessionID ?? ""))) continue
for (const part of parts) {
delete store.part_text_accum_delta[part.id]
}
delete store.part[key]
}
@@ -41,6 +41,7 @@ export function trimSessions(
.filter((s) => !s.time?.archived)
.sort((a, b) => cmp(a.id, b.id))
const roots = all.filter((s) => !s.parentID)
roots.sort(compareSessionRecent)
const children = all.filter((s) => !!s.parentID)
const base = roots.slice(0, limit)
const recent = takeRecentSessions(roots.slice(limit), SESSION_RECENT_LIMIT, cutoff)
@@ -46,6 +46,7 @@ export type State = {
session_status: {
[sessionID: string]: SessionStatus
}
session_working(id: string): boolean
session_diff: {
[sessionID: string]: SnapshotFileDiff[]
}
@@ -72,6 +73,9 @@ export type State = {
part: {
[messageID: string]: Part[]
}
part_text_accum_delta: {
[partID: string]: string
}
}
export type VcsCache = {
+13
View File
@@ -43,6 +43,7 @@ type SessionView = {
reviewOpen?: string[]
pendingMessage?: string
pendingMessageAt?: number
todoCollapsed?: boolean
}
type TabHandoff = {
@@ -759,6 +760,18 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
setScroll(tab: string, pos: SessionScroll) {
scroll.setScroll(key(), tab, pos)
},
todoCollapsed: {
get: () => s().todoCollapsed ?? false,
set(collapsed: boolean) {
const session = key()
const current = store.sessionView[session]
if (!current) {
setStore("sessionView", session, { scroll: {}, todoCollapsed: collapsed })
} else {
setStore("sessionView", session, "todoCollapsed", collapsed)
}
},
},
terminal: {
opened: terminalOpened,
open() {
+13 -5
View File
@@ -44,7 +44,7 @@ const migrate = (value: unknown) => {
}
const clone = (value: State | undefined) => {
if (!value) return undefined
if (!value) return
return {
...value,
model: value.model ? { ...value.model } : undefined,
@@ -104,7 +104,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
const pickAgent = (name: string | undefined) => {
const items = list()
if (items.length === 0) return undefined
if (items.length === 0) return
return items.find((item) => item.name === name) ?? items[0]
}
@@ -227,14 +227,14 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
() => agent.current()?.model,
fallback,
)
if (!item) return undefined
if (!item) return
return models.find(item)
}
const configured = () => {
const item = agent.current()
const model = current()
if (!item || !model) return undefined
if (!item || !model) return
return getConfiguredAgentVariant({
agent: { model: item.model, variant: item.variant },
model: { providerID: model.provider.id, modelID: model.id, variants: model.variants },
@@ -314,11 +314,16 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
configured,
selected,
current() {
return resolveModelVariant({
const resolved = resolveModelVariant({
variants: this.list(),
selected: this.selected(),
configured: this.configured(),
})
if (resolved) return resolved
const model = current()
if (!model) return
const saved = models.variant.get({ providerID: model.provider.id, modelID: model.id })
if (saved && this.list().includes(saved)) return saved
},
list() {
const item = current()
@@ -335,6 +340,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
variant: value ?? null,
})
write({ variant: value ?? null })
if (model) {
models.variant.set({ providerID: model.provider.id, modelID: model.id }, value ?? undefined)
}
})
},
cycle() {
+1
View File
@@ -276,6 +276,7 @@ export const dict = {
"mcp.status.connected": "متصل",
"mcp.status.failed": "فشل",
"mcp.status.needs_auth": "يحتاج إلى مصادقة",
"mcp.auth.clickToAuthenticate": "انقر للمصادقة",
"mcp.status.disabled": "معطل",
"dialog.fork.empty": "لا توجد رسائل للتفرع منها",
"dialog.directory.search.placeholder": "البحث في المجلدات",
+1
View File
@@ -276,6 +276,7 @@ export const dict = {
"mcp.status.connected": "conectado",
"mcp.status.failed": "falhou",
"mcp.status.needs_auth": "precisa de autenticação",
"mcp.auth.clickToAuthenticate": "Clique para autenticar",
"mcp.status.disabled": "desabilitado",
"dialog.fork.empty": "Nenhuma mensagem para bifurcar",
"dialog.directory.search.placeholder": "Buscar pastas",
+1
View File
@@ -300,6 +300,7 @@ export const dict = {
"mcp.status.connected": "povezano",
"mcp.status.failed": "neuspjelo",
"mcp.status.needs_auth": "potrebna autentifikacija",
"mcp.auth.clickToAuthenticate": "Kliknite za autentifikaciju",
"mcp.status.disabled": "onemogućeno",
"dialog.fork.empty": "Nema poruka za fork",
+1
View File
@@ -298,6 +298,7 @@ export const dict = {
"mcp.status.connected": "forbundet",
"mcp.status.failed": "mislykkedes",
"mcp.status.needs_auth": "kræver godkendelse",
"mcp.auth.clickToAuthenticate": "Klik for at godkende",
"mcp.status.disabled": "deaktiveret",
"dialog.fork.empty": "Ingen beskeder at forgrene fra",
+1
View File
@@ -282,6 +282,7 @@ export const dict = {
"mcp.status.connected": "verbunden",
"mcp.status.failed": "fehlgeschlagen",
"mcp.status.needs_auth": "benötigt Authentifizierung",
"mcp.auth.clickToAuthenticate": "Zum Authentifizieren klicken",
"mcp.status.disabled": "deaktiviert",
"dialog.fork.empty": "Keine Nachrichten zum Abzweigen vorhanden",
"dialog.directory.search.placeholder": "Ordner durchsuchen",
+3 -1
View File
@@ -25,6 +25,7 @@ export const dict = {
"command.project.open": "Open project",
"command.project.previous": "Previous project",
"command.project.next": "Next project",
"command.project.index": "Switch to project {{index}}",
"command.provider.connect": "Connect provider",
"command.server.switch": "Switch server",
"command.settings.open": "Open settings",
@@ -305,6 +306,7 @@ export const dict = {
"mcp.status.failed": "failed",
"mcp.status.needs_auth": "needs auth",
"mcp.status.disabled": "disabled",
"mcp.auth.clickToAuthenticate": "Click to authenticate",
"dialog.fork.empty": "No messages to fork from",
@@ -901,7 +903,7 @@ export const dict = {
"settings.permissions.tool.read.title": "Read",
"settings.permissions.tool.read.description": "Reading a file (matches the file path)",
"settings.permissions.tool.edit.title": "Edit",
"settings.permissions.tool.edit.description": "Modify files, including edits, writes, patches, and multi-edits",
"settings.permissions.tool.edit.description": "Modify files, including edits, writes, and patches",
"settings.permissions.tool.glob.title": "Glob",
"settings.permissions.tool.glob.description": "Match files using glob patterns",
"settings.permissions.tool.grep.title": "Grep",
+1
View File
@@ -299,6 +299,7 @@ export const dict = {
"mcp.status.connected": "conectado",
"mcp.status.failed": "fallido",
"mcp.status.needs_auth": "necesita auth",
"mcp.auth.clickToAuthenticate": "Haz clic para autenticar",
"mcp.status.disabled": "deshabilitado",
"dialog.fork.empty": "No hay mensajes desde donde bifurcar",
+1
View File
@@ -277,6 +277,7 @@ export const dict = {
"mcp.status.connected": "connecté",
"mcp.status.failed": "échoué",
"mcp.status.needs_auth": "nécessite auth",
"mcp.auth.clickToAuthenticate": "Cliquez pour vous authentifier",
"mcp.status.disabled": "désactivé",
"dialog.fork.empty": "Aucun message à partir duquel bifurquer",
"dialog.directory.search.placeholder": "Rechercher des dossiers",
+1
View File
@@ -275,6 +275,7 @@ export const dict = {
"mcp.status.connected": "接続済み",
"mcp.status.failed": "失敗",
"mcp.status.needs_auth": "認証が必要",
"mcp.auth.clickToAuthenticate": "クリックして認証",
"mcp.status.disabled": "無効",
"dialog.fork.empty": "フォーク元のメッセージがありません",
"dialog.directory.search.placeholder": "フォルダを検索",
+1
View File
@@ -275,6 +275,7 @@ export const dict = {
"mcp.status.connected": "연결됨",
"mcp.status.failed": "실패",
"mcp.status.needs_auth": "인증 필요",
"mcp.auth.clickToAuthenticate": "클릭하여 인증",
"mcp.status.disabled": "비활성화됨",
"dialog.fork.empty": "분기할 메시지 없음",
"dialog.directory.search.placeholder": "폴더 검색",

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