Compare commits

...

1018 Commits

Author SHA1 Message Date
Aiden Cline eb6b86c2c6 adjust action
publish-github-action / publish (push) Waiting to run
2025-10-16 13:15:27 -05:00
Adam 8f2667f395 wip: css/ui work 2025-10-16 18:06:59 +00:00
opencode 0e2bfb8a68 release: v0.15.5 2025-10-16 18:06:59 +00:00
Aiden Cline 9fd29cd301 ignore: tweak permissions 2025-10-16 12:48:39 -05:00
Aiden Cline 7e15176513 fix: github action (#3223) 2025-10-16 12:33:33 -05:00
Aiden Cline cc9f894b6a ci: fix changelog generation 2025-10-16 11:29:58 -05:00
Moisès Macià de19dd1d0a docs: fix misspelled word (#3211) 2025-10-16 10:04:11 -05:00
Dax Raad 2a49448e46 try to avoid persisting empty thinking/text blocks 2025-10-16 10:54:10 -04:00
opencode 20d03f40bb release: v0.15.4 2025-10-16 14:53:32 +00:00
GitHub Action dbb74ee4e0 ignore: update download stats 2025-10-16 2025-10-16 12:04:48 +00:00
seridescent c58da112ab fix: use ai-sdk openai chat language model instead of completion language model (#3204) 2025-10-16 00:59:49 -05:00
Aiden Cline 4973f281ff Revert "fix: Text content blocks must contain non-whitespace text" (#3200) 2025-10-15 20:02:17 -05:00
Dax Raad fa3cf830cb core: filter out alpha status models from provider list 2025-10-15 20:12:37 -04:00
Dax Raad fddfa2df68 ci: stuff 2025-10-15 19:59:46 -04:00
Dax Raad 093e6d7f88 snapshot publish everything 2025-10-15 19:53:14 -04:00
Dax Raad 1947cbd391 sync 2025-10-15 19:48:57 -04:00
Aiden Cline 01f635b7ba ignore: update readme 2025-10-15 16:06:11 -05:00
Aiden Cline 11d1eb5ccf Revert "fix: spawns hanging (#3192)"
This reverts commit 18fb335e6d.
2025-10-15 15:20:14 -05:00
Fabian Kukuck 5e394521d4 feat: make compact feature use streaming API (#3079)
Co-authored-by: fku <fabian.kukuck@ipt.ch>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2025-10-15 13:44:16 -05:00
Aiden Cline 18fb335e6d fix: spawns hanging (#3192) 2025-10-15 13:01:54 -05:00
Aiden Cline ac1b7b63b1 fix: Text content blocks must contain non-whitespace text (#3194) 2025-10-15 13:00:26 -05:00
Frank 5e074568b9 zen: support haiku 4.5 2025-10-15 13:53:00 -04:00
Matt Gillard e594d5a1ae updated bedrock provider for the new Australian sonnet 4.5 cross region inference (#3050)
Co-authored-by: Matt Gillard <matt-github@gillard.biz>
2025-10-15 11:09:22 -05:00
Haris Gušić a859ac532f Improve http error codes (#3186) 2025-10-15 10:53:09 -05:00
GitHub Action 4c3a4805e7 ignore: update download stats 2025-10-15 2025-10-15 12:04:51 +00:00
Frank 06a41df87b wip: zen 2025-10-15 02:55:01 -04:00
Aiden Cline 45caf66145 tweak: consolidate session lock logic (#3185) 2025-10-15 01:12:51 -05:00
Frank 557729caa0 wip: zen 2025-10-15 01:07:57 -04:00
Frank 2469578db8 wip: zen 2025-10-15 00:02:38 -04:00
Frank 471b915050 wip: zen 2025-10-14 23:45:06 -04:00
Frank f2698c4c4a wip: zen 2025-10-14 23:38:21 -04:00
Frank 333aadf23d wip: zen 2025-10-14 23:04:41 -04:00
Frank f5b00aa060 wip: zen 2025-10-14 23:03:13 -04:00
Dax Raad 38a2a69743 ci: run typecheck before tests to catch type errors early 2025-10-14 18:36:03 -04:00
Dax Raad 8aa4ea0eb1 try tsgo 2025-10-14 18:30:32 -04:00
Jay V bc10aca1d8 ignore: prompt 2025-10-14 17:45:10 -04:00
Jay V 6fef731af0 web: colocate copy button styles with components that use them 2025-10-14 17:41:17 -04:00
Frank 7052fff09f ci: fix 2025-10-14 17:22:29 -04:00
Frank 682a658819 wip: zen 2025-10-14 17:18:39 -04:00
Frank 3ab1bcd89b wip: zen 2025-10-14 17:13:21 -04:00
Frank 0a7e4d3320 wip: zen 2025-10-14 17:06:49 -04:00
Frank a4e0b35b9c wip: zen 2025-10-14 17:06:49 -04:00
Jay V fcf70461ac docs: improve MCP server configuration guidance with examples and caveats 2025-10-14 16:43:59 -04:00
Dax Raad 4170660b41 ci: channels 2025-10-14 15:09:18 -04:00
Dax Raad 926b8e37d7 sync 2025-10-14 14:57:34 -04:00
GitHub Action 889bafc911 chore: format code 2025-10-14 18:56:54 +00:00
Dax Raad d338407078 ci: test 2025-10-14 14:56:21 -04:00
Dax Raad d1aa28f417 ci: version stuff 2025-10-14 14:52:05 -04:00
Dax Raad 38bcff5998 ci: fix 2025-10-14 18:44:22 +00:00
opencode 00c74dbb72 release: v0.15.3 2025-10-14 18:44:21 +00:00
Dax Raad befa103109 ci: stuff 2025-10-14 14:35:04 -04:00
Aiden Cline 7520515273 fix: false positive package manager detection in upgrade (#3181) 2025-10-14 13:18:40 -05:00
Frank d15110074c ci: fix 2025-10-14 13:58:54 -04:00
Frank e91a051982 wip: zen 2025-10-14 13:52:30 -04:00
GitHub Action 1aa3dd2b56 chore: format code 2025-10-14 17:08:18 +00:00
Adam cf479404c3 wip: css/ui work 2025-10-14 12:07:45 -05:00
Adam 6b88402f08 wip: css/ui work 2025-10-14 12:06:18 -05:00
Adam b8cd2b62ca wip: desktop work 2025-10-14 12:06:17 -05:00
Netanel Draiman 97c4179bc5 feat(cli): add session option to attach command (#3167) 2025-10-14 11:04:32 -05:00
Adam afc475f9a4 wip: css and ui packages 2025-10-14 07:16:24 -05:00
Adam 4af079fd59 wip: desktop work 2025-10-14 07:15:08 -05:00
Adam 17f1cb3664 wip: desktop work 2025-10-14 07:15:08 -05:00
GitHub Action b4911ef1f1 ignore: update download stats 2025-10-14 2025-10-14 12:04:50 +00:00
Dax cacb086356 feat: use realtime events for live tool call updates in Slack (#3163) 2025-10-14 03:13:48 -04:00
Dax Raad 15409fc218 fix: update tsconfig for Slack package 2025-10-14 02:55:21 -04:00
Dax Raad de634a3f13 fix: export trimDiff function from edit tool 2025-10-14 02:55:02 -04:00
Dax Raad 07ac47ac3d fix: resolve TypeScript errors in SDK and Slack package 2025-10-14 02:54:37 -04:00
Dax Raad c64b823198 feat: add Slack integration package with Bolt framework 2025-10-14 02:53:55 -04:00
Dax Raad 87ff866318 core: improve dependency management and error handling for more reliable builds 2025-10-14 01:33:25 -04:00
Dax Raad b03301a967 core: standardize dependency versions for better reliability
Ensures consistent versions across packages by using workspace catalog for
tailwindcss and tsconfig dependencies, reducing potential conflicts and
installation issues.
2025-10-14 01:27:17 -04:00
Dax Raad 6e591ce3cb core: reduce dependency conflicts by standardizing package versions through catalog
This eliminates duplicate package versions that were causing build issues and
inconsistent behavior across the monorepo. Dependencies now resolve to single
versions through the workspace catalog, making installs faster and more reliable.
2025-10-14 01:23:54 -04:00
opencode 08840f2f32 release: v0.15.2 2025-10-14 04:56:00 +00:00
Alberto Fanton 17f1bb96f4 fix: disable GPG signing in snapshot tests (#3102) 2025-10-13 23:40:41 -05:00
Aiden Cline b22df18e0f fix: config dir overrides (#3160) 2025-10-13 23:25:53 -05:00
Aiden Cline 0beda25798 fix: custom model (#3156) 2025-10-13 19:58:19 -05:00
pancake 841135c435 fix: clang formatter name (#3042)
Co-authored-by: pancake <pancake@nopcode.org>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
2025-10-13 19:55:18 -05:00
Haris Gušić d4bc87f3c1 fix: make shell more robust (#3051) 2025-10-13 17:37:35 -05:00
maple 67e5252734 docs: typo in custom-tools.mdx (#3152) 2025-10-13 17:19:20 -05:00
Aiden Cline a0600e82d9 fix: typecheck (#3149) 2025-10-13 14:51:12 -05:00
AB 15d5c03f64 fix: add useCompletionUrls option to fix certain azure setups (#2528)
Co-authored-by: andreas.blass <andreas.blass@outlook.com>
Co-authored-by: GitHub Action <action@github.com>
2025-10-13 14:16:21 -05:00
Tommy D. Rossi e6373142c1 tweak: include stack trace in server error responses (#3134) 2025-10-13 14:10:35 -05:00
opencode 65b9b7acf0 release: v0.15.1 2025-10-13 18:14:52 +00:00
Dax Raad 6cc97ede65 fix: disable workspace symbol lookup to prevent LSP performance issues 2025-10-13 14:05:54 -04:00
Aiden Cline f8132999b6 fix: pass options to compact (#3136) 2025-10-13 10:42:39 -05:00
Aiden Cline 40f77361d2 docs: update recommended models list (#3121) 2025-10-12 21:35:31 -05:00
Aiden Cline 85bd863914 fix: adjust list tool prompt to handle cwd better (#3115) 2025-10-12 16:48:03 -05:00
Ravshan Samandarov 7122edc44f docs: Update README.md (#3100) 2025-10-12 16:23:25 -04:00
Jay 864a53775a docs: Fix formatting of num_ctx in providers.mdx 2025-10-12 16:01:32 -04:00
Aiden Cline 083fb7075f docs: ollama num_ctx (#3111) 2025-10-12 10:40:51 -05:00
GitHub Action 5c26d08fe7 ignore: update download stats 2025-10-12 2025-10-12 12:04:09 +00:00
OpeOginni 2e870df2b7 fix: add timeout to fetch models.dev refresh request (#3059) 2025-10-12 00:20:22 -05:00
opencode 8680e728d7 release: v0.15.0 2025-10-12 05:12:15 +00:00
Dax Raad e025027d20 ci: centralize bun setup to reduce duplication and improve caching 2025-10-12 00:46:37 -04:00
Dax Raad bac8e924be ci: tweak 2025-10-12 00:40:59 -04:00
Tommy D. Rossi c015ced81f fix: rg hanging forever when run in bash, waiting for stdin (#3103)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2025-10-11 23:24:48 -05:00
Dax Raad 4951bc5515 ci: re-enable aur 2025-10-12 00:22:16 -04:00
Frank 8f37e46b49 wip: zen 2025-10-11 16:17:39 -04:00
Frank b5114e1aea ci: fix 2025-10-11 15:08:45 -04:00
Frank 47a76e92d5 wip: zen 2025-10-11 15:07:06 -04:00
Frank 59a3df970f wip: zen 2025-10-11 14:48:34 -04:00
Frank cbe402ca4a ci: fix 2025-10-11 14:41:52 -04:00
Frank 39262874ec wip: zen 2025-10-11 14:38:53 -04:00
Frank 45e55b730b Bump sst to latest 2025-10-11 14:38:45 -04:00
Frank cfc3b20826 wip: zen 2025-10-11 10:51:17 -04:00
Frank a1f7dc98fa wip: zen 2025-10-11 09:29:26 -04:00
Frank eb20c411b9 wip: zen 2025-10-11 08:27:32 -04:00
Frank c8f39d6065 wip: zen 2025-10-11 08:27:32 -04:00
Frank b7478b7be3 wip: zen 2025-10-11 08:27:32 -04:00
GitHub Action a31601dd37 ignore: update download stats 2025-10-11 2025-10-11 12:04:02 +00:00
Frank 7e8c7c329a wip: zen refactor selector 2025-10-11 07:54:57 -04:00
Frank 64d857aa08 wip: zen fix drop down style 2025-10-11 07:15:19 -04:00
Frank 0d7543c5b4 wip: zen fix template 2025-10-11 06:33:47 -04:00
Dax Raad 0271b3847f ci: fixes 2025-10-11 00:24:35 -04:00
Dax Raad a2e1a61cfb ci: stuff 2025-10-11 00:06:46 -04:00
Dax Raad 5685689512 ci: fix 2025-10-10 23:43:32 -04:00
Frank d180adb7fc wip: zen 2025-10-10 21:26:16 -04:00
Frank efa75c9697 Merge branch 'console-workspaces' into dev 2025-10-10 21:24:05 -04:00
Frank dfd154e760 wip: zen 2025-10-10 21:21:55 -04:00
Frank 70bd275955 wip: zen 2025-10-10 20:32:28 -04:00
Frank 77c0b1b724 wip: zen 2025-10-10 20:30:13 -04:00
Frank 2222036bd2 wip: zen 2025-10-10 20:16:44 -04:00
Frank d93dcc7a0a wip: zen 2025-10-10 20:02:17 -04:00
Frank 3026dafb3d wip: zen 2025-10-10 19:56:40 -04:00
Frank 3b30bdf8ec wip: zen 2025-10-10 19:49:59 -04:00
Frank 2a9f5bbd38 wip: zen 2025-10-10 19:39:01 -04:00
Dax Raad 171c591728 ci: fixes 2025-10-10 18:17:10 -04:00
Dax Raad fd928f3692 ci: fix 2025-10-10 18:11:19 -04:00
Dax Raad a35544f5a2 ci: stuff 2025-10-10 18:04:08 -04:00
Dax Raad d574e62490 ci: stuff 2025-10-10 17:56:33 -04:00
Dax Raad 93c84b47ae upgrade to bun 1.3.0 2025-10-10 17:53:32 -04:00
Frank b0a6e71560 wip: zen 2025-10-10 16:42:27 -04:00
Frank b97f117628 wip: zen 2025-10-10 16:34:07 -04:00
Frank 9e482a74ae wip: zen 2025-10-10 16:04:06 -04:00
Frank 2aa7d6469a wip: zen 2025-10-10 14:54:49 -04:00
Frank c278117d31 wip: zen 2025-10-10 14:19:06 -04:00
Frank 5f04fe3783 wip: zen 2025-10-10 14:11:48 -04:00
Frank 82c0dff231 wip: zen 2025-10-10 13:52:54 -04:00
Frank 5722df88b8 wip: zen style members 2025-10-10 13:48:56 -04:00
Frank 8fa81a2f30 wip: zen style api keys 2025-10-10 13:45:06 -04:00
Frank dcc0d265d8 wip: zen 2025-10-10 13:26:39 -04:00
Frank df3df34f58 wip: zen 2025-10-10 13:21:51 -04:00
Frank e216501503 wip: zen 2025-10-10 12:46:42 -04:00
Rustafarian Dev b2f35389fb fix: perl6 file extension (#3066) 2025-10-10 11:28:49 -05:00
Frank 218e6f1b3d wip: zen 2025-10-10 12:22:36 -04:00
Frank d397a4e236 wip: sync 2025-10-10 12:16:57 -04:00
Frank 7bbb3a4dcf wip: zen settings 2025-10-10 12:04:02 -04:00
Frank c9ab1ab8aa wip: zen 2025-10-10 09:03:49 -04:00
GitHub Action c5e080fc6f ignore: update download stats 2025-10-10 2025-10-10 12:04:18 +00:00
Frank bff8338a97 wip: zen style byok 2025-10-10 03:15:55 -04:00
Frank 09dbfd3e28 wip: zen style byok 2025-10-10 02:53:05 -04:00
Frank 2bf5d8d823 wip: zen style byok 2025-10-10 02:37:50 -04:00
Frank 931dc855ce wip: style byok 2025-10-10 02:34:06 -04:00
Frank 5de6ade823 wip: zen 2025-10-10 01:36:15 -04:00
Frank 95f3c7fda5 wip: zen style nav bar 2025-10-10 00:56:16 -04:00
Frank 36c73b3046 wip: zen style model 2025-10-10 00:02:04 -04:00
Dax Raad f7d8b41976 core: improve directory validation error messages to help users fix invalid directory names 2025-10-09 22:40:23 -04:00
Frank d4f0b8b483 wip: zen style header 2025-10-09 22:38:42 -04:00
Dax Raad 367cf7eac3 ensure @opencode-ai/plugin is available in .opencode folder 2025-10-09 21:18:49 -04:00
opencode 7ddc833674 release: v0.14.7 2025-10-10 01:02:37 +00:00
Dax Raad 1076fc244c drop excess dependency in opencode sdk 2025-10-09 20:55:25 -04:00
Dax Raad a0844a6b85 core: use platform-specific watcher backends for better file system monitoring 2025-10-09 18:29:18 -04:00
Dax Raad 21e2f45f77 core: replace chokidar with @parcel/watcher for better performance and cross-platform support 2025-10-09 18:21:38 -04:00
Frank 000ed1a066 wip: zen 2025-10-09 17:18:55 -04:00
Dax Raad c50d7a4275 ignore: add common build and framework directories to ignore list 2025-10-09 16:35:56 -04:00
Frank 9e50700b50 wip: zen nav bar 2025-10-09 16:01:52 -04:00
Dax Raad 92f106f740 ignore: improve file ignore performance and cross-platform support
- Replace glob patterns with Set lookup for common folders to speed up matching
- Use path.sep for cross-platform compatibility on Windows/Unix systems
- Add comprehensive test coverage for nested and non-nested folder matching
- Simplify implementation by removing unnecessary caching complexity
2025-10-09 15:54:01 -04:00
Adam 611a719fb5 feat: experimental skip bootstrap 2025-10-09 14:51:11 -05:00
Aiden Cline bf447bd5ae docs: fix bugged example (#3068) 2025-10-09 12:21:44 -05:00
Jay V 84a75f3d93 docs: adding tools doc 2025-10-09 13:19:51 -04:00
Jay V b407c00c84 docs: document ripgrep .ignore file override in tools 2025-10-09 13:19:51 -04:00
Jay V 38aeafea30 docs: adding spellcheck command 2025-10-09 13:19:51 -04:00
Aiden Cline 73cc3e1a95 feat: allow read tool to handle images (#3052) 2025-10-09 09:05:11 -05:00
GitHub Action 330e5c3386 ignore: update download stats 2025-10-09 2025-10-09 12:04:27 +00:00
Dax Raad 03d8a3f6a2 lsp: fix root detection to use instance directory instead of worktree 2025-10-09 04:30:30 -04:00
Dax Raad 73c7dacc09 lsp: simplify language server root detection to use lock files
Improves project boundary detection by focusing on package manager lock files instead of config files, providing more reliable workspace identification across different project types.
2025-10-09 04:22:38 -04:00
Haris Gušić bf2382d900 fix: process.stdout.write instead of console.log for export cmd (#3049) 2025-10-09 00:46:19 -05:00
Frank f5fe5252d7 wip: zen 2025-10-08 22:33:20 -04:00
Frank ceca472e8c wip: zen 2025-10-08 18:59:41 -04:00
Frank 28335d273b wip: zen 2025-10-08 17:03:42 -04:00
Frank 5df90e43df wip: zen 2025-10-08 15:20:50 -04:00
Frank 9f5111d21f wip: zen 2025-10-08 13:31:15 -04:00
Jay V d02ff9c5b1 docs: fix permission docs 2025-10-08 12:13:42 -04:00
GitHub Action 7717e3f355 ignore: update download stats 2025-10-08 2025-10-08 12:04:31 +00:00
Adam cfe96f6551 fix(tui): suggestions gap on home page 2025-10-08 06:56:18 -05:00
Dax Raad 8fcf52a3cd add free workspace 2025-10-08 02:27:01 -04:00
Frank 861fdc01cf wip: zen 2025-10-08 01:14:39 -04:00
Frank df53506975 wip: zen 2025-10-08 00:03:36 -04:00
opencode 7cae3cc86a release: v0.14.6 2025-10-07 19:59:08 +00:00
Dax Raad b47f5ac785 fix issue with blank new version popup 2025-10-07 15:51:59 -04:00
Frank 9071c94b13 wip: zen 2025-10-07 13:37:38 -04:00
Aiden Cline 21d4459d5e docs: troubleshooting ProviderModelNotFoundError (#3016) 2025-10-07 11:50:37 -05:00
Sai 6f4e3f519e docs: add agent specific permission example (#3009) 2025-10-07 10:08:52 -05:00
Frank cdd652e830 wip: zen 2025-10-07 09:17:08 -04:00
GitHub Action a6491a2f4e ignore: update download stats 2025-10-07 2025-10-07 12:04:53 +00:00
Dax Raad 06fc3bc28f core: improve MCP reliability and add status monitoring
- Added 5-second timeout to MCP client verification to prevent hanging connections
- New GET /mcp endpoint to monitor server connection status
- Automatically removes unresponsive MCP clients during initialization
2025-10-07 04:04:19 -04:00
opencode b5ff5ae621 release: v0.14.5 2025-10-07 06:21:31 +00:00
Aiden Cline cbf11adac7 fix: mcp error (#3006) 2025-10-07 00:45:46 -05:00
Aiden Cline 546c4667a6 tweak: grep tool to handle single file better (#3004) 2025-10-06 23:24:00 -05:00
Frank 83253ffabf wip: zen 2025-10-06 23:57:55 -04:00
Frank e52712ca97 wip: zen 2025-10-06 23:57:54 -04:00
opencode 9389c710f9 release: v0.14.4 2025-10-07 03:32:10 +00:00
Dax Raad ac12364c27 ignore: 2025-10-06 23:25:01 -04:00
Dax Raad cb40e8c622 core: restore bash command security validation to prevent accidental directory traversal
The permission validation that prevents commands from accessing paths outside the project directory was accidentally disabled, which could allow commands like 'cd ../' to escape the workspace. This restores the security check that keeps your commands safely contained within your project boundaries.
2025-10-06 23:24:18 -04:00
Dax Raad 87f71e2183 core: improve session API reliability with proper input validation 2025-10-06 19:37:44 -04:00
Dax Raad fb6713c2b8 Update todo tool to use centralized Todo module 2025-10-06 18:54:05 -04:00
Dax Raad b7e953c077 Add missing files and fix type aliases for opentui features 2025-10-06 18:53:35 -04:00
Dax Raad a06cba9d2e Add todo list and session forking API endpoints 2025-10-06 18:51:57 -04:00
Dax Raad 389bc1f8da Add session forking functionality and simplify remove logic 2025-10-06 18:50:56 -04:00
Frank eeff55f681 wip: zen 2025-10-06 17:23:10 -04:00
Frank 176069efe8 wip: zen 2025-10-06 17:17:02 -04:00
Frank 994a0842eb wip: zen 2025-10-06 17:13:19 -04:00
Frank 687d68eee6 wip: zen 2025-10-06 17:13:19 -04:00
Jay V 81faff475f docs: update footer 2025-10-06 17:05:45 -04:00
Jay V ac88e0937c docs: fix styles and zen doc, closes #2912 2025-10-06 17:00:10 -04:00
Jay V e9729e4b8c docs: share page css 2025-10-06 16:13:21 -04:00
GitHub Action a9230df6b8 ignore: update download stats 2025-10-06 2025-10-06 12:04:17 +00:00
Aiden Cline 140f1a0600 fix: add timeout message if command times out (#2986) 2025-10-05 23:55:01 -05:00
Mani Sundararajan 6d6fc43bb5 fix: file references & grep tool for windows (#2980) 2025-10-05 14:32:07 -05:00
GitHub Action 181c38c9b6 ignore: update download stats 2025-10-05 2025-10-05 12:03:55 +00:00
opencode 601b282459 release: v0.14.3 2025-10-05 11:22:57 +00:00
Dax Raad b57897e377 ci: publish 2025-10-05 07:14:52 -04:00
Dax Raad 62a52c5539 ci: disable aur 2025-10-05 07:12:33 -04:00
Dax Raad fd61b7dbc0 sdk: simplify getting started with single createOpencode function
Makes it easier for developers to get started by providing a single function that creates both server and client, removing the need to manually coordinate separate server and client creation
2025-10-05 07:01:32 -04:00
Dax Raad b59be49095 sdk: simplify getting started with single createOpencode function
Makes it easier for developers to get started by providing a single function that creates both server and client, removing the need to manually coordinate separate server and client creation
2025-10-05 07:00:29 -04:00
Aiden Cline 431312634c fix: max output tokens when using large thinking budget (#2976) 2025-10-04 23:38:41 -05:00
Dax Raad 9348fdec34 sync 2025-10-04 21:33:47 -04:00
Aiden Cline 8f6c63c017 fix: allow LSP filename matching when extension is missing (#2975) 2025-10-04 20:30:53 -05:00
iwauo 4603820839 docs: java-lsp support (#2958) 2025-10-04 11:28:09 -05:00
GitHub Action 7b359f8cd8 ignore: update download stats 2025-10-04 2025-10-04 12:03:53 +00:00
Frank a357abefe1 wip: zen 2025-10-04 01:12:32 -04:00
Yuku Kotani 4c60276d10 feat: Vertex AI support; add google-vertex and google-vertex-anthropic providers (#2347) 2025-10-04 01:10:38 -04:00
Aiden Cline 929ef83d3d add command to debug config (#2962) 2025-10-03 23:07:58 -05:00
Frank 7b627b7610 wip: zen 2025-10-03 23:48:34 -04:00
Dax Raad a61ca2e5bf ci: try regional hostname again 2025-10-03 19:05:32 -04:00
Rovshan Muradov 247f9f8e10 docs: Update models.mdx (#2916) 2025-10-03 17:06:20 -04:00
Frank e55a161f4d wip: zen 2025-10-03 16:32:53 -04:00
Jay V b7fc1a16f9 docs: rename opencode to OpenCode 2025-10-03 13:46:56 -04:00
Frank 31534913a4 wip: zen 2025-10-03 12:54:52 -04:00
Adam 165959715e fix: github stats 2025-10-03 09:34:17 -05:00
Adam bc9d3b308a fix: user-agent 2025-10-03 09:30:51 -05:00
Adam 4ac32d5932 chore: user-agent header 2025-10-03 09:27:12 -05:00
Adam 18d58612ad chore: logging errors 2025-10-03 09:19:54 -05:00
Adam 28bb12bae2 chore: logging errors 2025-10-03 09:10:33 -05:00
Adam 9cad9ffc23 chore: app -> desktop 2025-10-03 09:04:28 -05:00
Frank 44e295600a wip: zen 2025-10-03 08:25:51 -04:00
GitHub Action 7cf05a027b ignore: update download stats 2025-10-03 2025-10-03 12:04:07 +00:00
Frank 0fe315d210 wip: zen 2025-10-03 07:36:16 -04:00
Frank c688305dfc wip: zen 2025-10-03 07:36:16 -04:00
Frank 97a825a8b6 wip: zen 2025-10-03 07:36:16 -04:00
Dax Raad fbfaf15bfc ci: stuff 2025-10-03 10:53:10 +00:00
opencode e4c33da6d4 release: v0.14.1 2025-10-03 10:53:10 +00:00
Dax Raad 2cb3255556 turn on codex medium reasoning again 2025-10-03 06:46:07 -04:00
David Hill cc62b8d8b6 Firefox email input fix 2025-10-02 23:50:51 +01:00
Jay 61003ff55d docs: update theme (#2929)
Co-authored-by: David Hill <iamdavidhill@gmail.com>
2025-10-02 23:20:30 +01:00
David Hill 95daf247d3 Update index.css 2025-10-02 23:19:53 +01:00
Jay 1952e5f46f ignore: Workspace updates (#2930)
Co-authored-by: David Hill <iamdavidhill@gmail.com>
2025-10-02 23:18:57 +01:00
Frank 68fd879f76 wip: zen 2025-10-02 18:16:29 -04:00
Frank af83f14bb7 wip: zen 2025-10-02 17:55:54 -04:00
Frank b58c12d47a wip: zen 2025-10-02 16:09:42 -04:00
Frank 9168c974c5 wip: zen 2025-10-02 13:58:40 -04:00
Jay cc4e4d37d1 docs: README 2025-10-02 12:33:32 -04:00
Jay V c31b0ec014 docs: update README 2025-10-02 12:31:58 -04:00
David Hill 4659e0ed35 Copy tweaks 2025-10-02 17:02:33 +01:00
David Hill 215943e39f Border top only on safari fix 2025-10-02 16:55:48 +01:00
David Hill 493d9194d7 Update favicon.svg 2025-10-02 16:55:29 +01:00
Aiden Cline f58fe4e866 fix: run cmd json format when running command (#2926) 2025-10-02 10:37:42 -05:00
David Hill 8831a57e5f Style fixes 2025-10-02 16:35:23 +01:00
David Hill e1e0015be4 Update dock.png 2025-10-02 16:24:14 +01:00
David Hill fdbdf5ef20 Update dock.png 2025-10-02 16:14:52 +01:00
David Hill a3711c0c81 Email input color fix 2025-10-02 16:11:55 +01:00
David Hill 7b23a64e82 Update dock.png 2025-10-02 15:50:56 +01:00
David Hill 2164190b93 Testimonial tweaks 2025-10-02 15:37:36 +01:00
David Hill 78cac1a32c Merge branch 'dev' of https://github.com/sst/opencode into dev 2025-10-02 15:37:13 +01:00
David Hill f1a916d788 faq icon fix 2025-10-02 15:37:10 +01:00
Frank 50f2bf2432 ignore: fix 2025-10-02 10:10:07 -04:00
David Hill 08fe1472a3 Merge branch 'dev' of https://github.com/sst/opencode into dev 2025-10-02 15:03:59 +01:00
David Hill f3ca14cff4 Body background fix 2025-10-02 15:03:56 +01:00
David Hill b614a6f03a Mobile nav icon fix 2025-10-02 15:02:57 +01:00
David Hill a69708f3f3 Mobile nav icon fix 2025-10-02 15:02:44 +01:00
David Hill 5c2fea2b30 Mobile nav fix 2025-10-02 15:01:22 +01:00
Adam cc58dbe6b4 fix: broken links 2025-10-02 09:00:33 -05:00
David Hill db10eac89e Update posters for videos 2025-10-02 14:55:38 +01:00
David Hill fcded3dc6e Merge branch 'dev' of https://github.com/sst/opencode into dev 2025-10-02 14:54:16 +01:00
David Hill 38b587153e Testimonial tweak 2025-10-02 14:53:54 +01:00
Adam 14ad4e4318 chore: add email signup back 2025-10-02 08:46:25 -05:00
David Hill ad4d778e31 Update faq.tsx 2025-10-02 14:42:49 +01:00
David Hill e1f0b4d247 Faq icon color fix 2025-10-02 14:41:57 +01:00
Adam decfbeee01 fix: testimonial link 2025-10-02 08:34:22 -05:00
Adam 99e438c806 wip: desktop work 2025-10-02 08:34:01 -05:00
GitHub Action 5f1ac0af9b ignore: update download stats 2025-10-02 2025-10-02 12:04:06 +00:00
opencode dc159ecfc1 release: v0.14.0 2025-10-02 05:33:58 +00:00
Dax Raad 802334c3e9 ci: fix 2025-10-02 01:25:27 -04:00
Dax Raad 5e390b15d3 ci: publsih 2025-10-02 01:24:33 -04:00
Dax Raad 3195f8eb80 ci: test 2025-10-02 01:19:53 -04:00
Dax Raad 0ee8e1b05f ci: install opencode 2025-10-02 01:19:53 -04:00
Dax Raad 5dfb03ea0a ci: fix 2025-10-02 05:18:01 +00:00
opencode 93b3607250 release: v0.13.9 2025-10-02 05:18:01 +00:00
Dax Raad 9f73e3c9b6 ci: sync 2025-10-02 01:09:58 -04:00
Dax Raad 43c7b7a765 ci: stuff 2025-10-02 01:08:29 -04:00
Aiden Cline b842cc5e7c docs: fix install fmt (#2914) 2025-10-01 23:32:39 -05:00
Aiden Cline 8fb3c65eee docs: fix more links (#2913) 2025-10-01 23:22:17 -05:00
Sandip Wane cf363fe67a chore: rm empty try-catch block (#2769)
Co-authored-by: Sandip Wane <sandip.wane@cloudhedge.io>
2025-10-01 23:21:57 -05:00
Dax Raad d0008024f1 core: fix file search limit handling and ensure File module initialization 2025-10-02 00:18:18 -04:00
opencode f7c5281d47 release: v0.13.8 2025-10-02 04:16:48 +00:00
Dax Raad 8cd3078df4 core: improve file search reliability and performance 2025-10-02 00:09:02 -04:00
Aiden Cline 628a15d382 docs: fix (#2910) 2025-10-01 22:20:35 -05:00
Jay V ab51603d1b docs: hide email signup 2025-10-01 20:16:02 -04:00
Jay V f3d895f652 docs: testimonials 2025-10-01 19:57:17 -04:00
Dax Raad e220fa841a wip: lander 2025-10-01 19:54:58 -04:00
Jay V 30feacb006 docs: fix link 2025-10-01 19:52:31 -04:00
Dax Raad cb4c962d71 wip: lander 2025-10-01 19:49:00 -04:00
Dax Raad c3416825d8 ignore: fix 2025-10-01 19:40:56 -04:00
Dax dcce094f1e Zen lander (#2907)
Co-authored-by: David Hill <iamdavidhill@gmail.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
Co-authored-by: Jay V <air@live.ca>
2025-10-01 19:38:15 -04:00
Frank 3cdb7b2d6f wip: zen 2025-10-01 19:34:37 -04:00
Frank 69d504f4be doc: update zen pricing 2025-10-01 17:48:12 -04:00
GitHub Action f84e912391 ignore: update download stats 2025-10-01 2025-10-01 12:04:26 +00:00
Dax Raad 7810be5885 core: remove redundant patch integration test
The integration test was duplicating coverage already provided by the comprehensive
patch namespace tests. Users benefit from faster test runs without losing any
coverage of patch functionality. The remaining tests provide complete validation
of patch parsing, application, and tool integration.
2025-10-01 06:49:19 -04:00
Dax Raad c338173f7a core: make patch tool more reliable and consistent with other editing tools
The patch tool now works seamlessly alongside other file editing tools with improved
error handling and a more intuitive permission system. Users will experience:

- More reliable patch application with better error messages
- Consistent permission prompts that match other editing tools
- Smoother integration when applying complex multi-file changes
- Better feedback on what changes are being made before applying patches

This refactoring leverages the robust patch parsing engine while making the tool
feel native to the opencode workflow, reducing friction when making bulk changes
to your codebase.
2025-10-01 06:45:43 -04:00
opencode 71da1ec86a release: v0.13.7 2025-10-01 09:13:16 +00:00
Dax Raad 282c1e1d9d codex should not have reasoning effort 2025-10-01 05:06:37 -04:00
Dax Raad ee4e201045 core: prevent file deletion when reverting changes to existing files 2025-10-01 05:06:37 -04:00
opencode 2e1ed2fc65 release: v0.13.6 2025-10-01 07:44:18 +00:00
Dax Raad 8ad4813f46 overhaul file search and support @ mentioning directories 2025-10-01 03:37:01 -04:00
Aiden Cline af71bc7084 fix: adjust model dialog to handle same model id but different names (#2881) 2025-09-30 11:43:57 -05:00
GitHub Action c59928a840 ignore: update download stats 2025-09-30 2025-09-30 12:04:27 +00:00
Dax Raad a82a7f8bd9 update anthropic system prompts 2025-09-30 04:41:36 -04:00
Aiden Cline 64b3b456ff fix: tui stuck saying generating... even when it is done (#2872) 2025-09-29 23:55:47 -05:00
Aiden Cline 539d438d97 fix: worktree cmd (#2870) 2025-09-29 22:21:54 -05:00
Frank abbae010da wip: zen 2025-09-29 14:17:53 -04:00
opencode 6700d00543 release: v0.13.5 2025-09-29 14:12:58 +00:00
Aiden Cline 08b8ff2671 fix: bash regex (#2858) 2025-09-29 08:51:46 -05:00
GitHub Action 4e21bfce23 ignore: update download stats 2025-09-29 2025-09-29 12:04:29 +00:00
Giuseppe Rota edf274ff9d docs: document model id behavior (#2856) 2025-09-29 06:52:26 -05:00
opencode 83484d52de release: v0.13.4 2025-09-29 05:53:07 +00:00
Dax Raad 370a9572ed ci: fix homebrew 2025-09-29 01:40:27 -04:00
Dax Raad 3f2da89007 release: v0.13.2 2025-09-29 01:38:53 -04:00
Dax Raad 112a3685fb ci: publish 2025-09-29 01:24:35 -04:00
Dax Raad 3cb9218b98 ci: fix 2025-09-29 01:22:39 -04:00
Dax Raad 3542e6b051 ci: fix 2025-09-29 01:06:12 -04:00
Aiden Cline 2a41938ad8 ignore: go mod tidy (#2851) 2025-09-28 23:05:56 -05:00
Frank 75d871fd49 wip: zen 2025-09-28 19:55:40 -04:00
Frank 12740d1d17 wip: zen 2025-09-28 19:55:40 -04:00
Dax Raad adab4bcddf core: improve webfetch tool content negotiation and format handling 2025-09-28 17:57:50 -04:00
Frank f6406c2a60 wip: zen 2025-09-28 12:49:28 -04:00
GitHub Action 4be998a4f5 ignore: update download stats 2025-09-28 2025-09-28 12:03:57 +00:00
Frank 27c0709de8 wip: zen 2025-09-27 21:53:50 -04:00
Aiden Cline e1e0b58991 respect model id in opencode.json (#2833) 2025-09-27 17:09:21 -05:00
Aurélien Tollard e98b50d197 Fix: Set OPENCODE_CALLER env in a more portable way for vscode extension (#2230) 2025-09-27 10:36:24 -04:00
Frank be0a55d146 wip: zen 2025-09-27 10:19:58 -04:00
Frank c012dbc85a wip: zen 2025-09-27 10:05:19 -04:00
GitHub Action 3913040ea1 ignore: update download stats 2025-09-27 2025-09-27 12:04:01 +00:00
Dax Raad 6de9e29979 ci: tweaks 2025-09-27 04:12:55 -04:00
Dax Raad f5218e2577 sync 2025-09-27 04:10:56 -04:00
Arjun Singh 72295261e6 Include step-start and step-finish for cost tracking (#2810) 2025-09-27 03:45:36 -04:00
Dax Raad 8eee14c19c ci: wtf 2025-09-27 03:20:08 -04:00
Dax Raad 96e5bfdd4f ci: fix 2025-09-27 03:19:34 -04:00
Dax Raad 139113f9c3 core: configure turbo to avoid building opencode for web tests 2025-09-27 03:19:29 -04:00
Dax Raad d69068dabd ci: fix 2025-09-27 03:18:12 -04:00
Dax Raad 3a20194084 ci: test 2025-09-27 03:17:22 -04:00
Dax Raad 1908ed7a49 core: fix config test by removing model field expectation 2025-09-27 03:10:01 -04:00
Dax Raad 29541c54ce ci: fix git identity in test workflow 2025-09-27 03:07:37 -04:00
Dax Raad fc1cf01a26 ci: improve test coverage 2025-09-27 03:04:42 -04:00
Dax Raad 56d0e8acbf sync 2025-09-27 02:53:20 -04:00
Dax Raad ffe37d6d98 ci: format 2025-09-27 02:22:03 -04:00
Dax Raad 4855f3133d wip: bun test improvements 2025-09-27 02:17:08 -04:00
Dax Raad 7eba61cd25 ci: give up 2025-09-27 01:51:54 -04:00
Dax Raad b24319fe80 ci: add regional hostname 2025-09-27 01:28:11 -04:00
Dax Raad 7bb0ff2fc6 fix zen cookie 2025-09-27 01:12:25 -04:00
opencode cec0844cd6 release: v0.12.1 2025-09-26 21:18:45 +00:00
Frank 27bbecd0e1 zen: accept tax id 2025-09-26 17:10:45 -04:00
Timo Clasen 76f06b08cb fix(tool): follow symlinks when looking for tools (#2809) 2025-09-26 16:01:08 -05:00
opencode 5c58cd7b3f release: v0.12.0 2025-09-26 20:55:00 +00:00
Frank 95313b660e zen: model management helper 2025-09-26 15:18:24 -04:00
sonsulee fb9ca7162c docs: add TUI configuration options and examples (#2212)
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Jay <air@live.ca>
2025-09-26 13:09:46 -04:00
Yihui Khuu cfb031681e fix: config loading not considering symlinks (#2800) 2025-09-26 09:46:49 -05:00
GitHub Action a053b93ac8 ignore: update download stats 2025-09-26 2025-09-26 12:04:26 +00:00
Dax Raad 05767142ca ci: fix deploy 2025-09-26 11:57:49 +00:00
opencode f669e88e2a release: v0.11.8 2025-09-26 11:57:49 +00:00
Dax Raad eb38e0b40e disable aggressive config validation 2025-09-26 07:51:53 -04:00
opencode 76fc05e0e3 release: v0.11.7 2025-09-26 11:19:15 +00:00
Adam d9bd7de976 fix(tui): cursor position 2025-09-26 06:13:23 -05:00
Dax Raad 0e65537c97 core: add themes to allowed config directories 2025-09-26 06:40:41 -04:00
opencode 48d6bbc90c release: v0.11.6 2025-09-26 09:52:23 +00:00
Dax Raad 180f493ac0 tui: fix cursor position offset in home screen 2025-09-26 05:46:16 -04:00
opencode ca1622aef9 release: v0.11.5 2025-09-26 09:40:16 +00:00
Dax Raad 766ca1b32a fix erroring on custom tool folder 2025-09-26 05:33:38 -04:00
Dax Raad 9afee84247 validate config directory 2025-09-26 03:23:25 -04:00
Dax Raad 6b4c0076e8 core: add config update endpoint and functionality 2025-09-26 02:37:19 -04:00
Dax Raad e314b5a3b8 ci: ignore 2025-09-26 02:01:19 -04:00
Dax Raad ef37a4fe55 ci: setup husky pre-push hook to run typecheck 2025-09-26 02:01:19 -04:00
opencode f4b2b4934b release: v0.11.4 2025-09-26 05:56:03 +00:00
Dax Raad 8c44ba84cd tui: fix opencode logo spacing in home view 2025-09-26 01:40:32 -04:00
Dax Raad fd44632de8 turn reasoning summaries back on by default for zen 2025-09-26 01:37:44 -04:00
Dax Raad 50fd5fc640 core: enable reasoning.encrypted_content and reasoningSummary for opencode provider\ntui: adjust editorY position calculation 2025-09-26 01:27:53 -04:00
Aiden Cline 428b443795 fix: openai reasoning issue (#2780) 2025-09-26 01:23:30 -04:00
Aiden Cline d467db43b0 tweak: include usage by default for openai compatible providers (#2788) 2025-09-25 21:06:58 -05:00
David Hill d11ad9226a Update opencode logo 2025-09-25 23:22:50 +01:00
Frank fc262ad255 zen: track tps 2025-09-25 17:56:41 -04:00
Frank cfbe5fd908 zen: check balance on enable billing 2025-09-25 17:47:50 -04:00
Frank 42263fe0c5 zen: fix parsing cache write tokens 2025-09-25 17:02:23 -04:00
Adam 22b70d6510 wip: better desktop file status state and timeline 2025-09-25 14:41:31 -05:00
Adam 0d05ab5be7 wip: watch select .git files in watcher 2025-09-25 14:41:31 -05:00
GitHub Action fd322e28e8 ignore: update download stats 2025-09-25 2025-09-25 12:04:27 +00:00
Frank f4e79269fc zen: billing 2025-09-24 21:26:04 -04:00
GitHub Action 0db03c4b4e chore: format code 2025-09-24 23:10:17 +00:00
Frank 91ac1783d9 zen: billing 2025-09-24 19:09:28 -04:00
Adam d8089f9bbd fix(app): changes view 2025-09-24 15:49:40 -05:00
Adam f66689254e feat(app): changes view 2025-09-24 15:46:33 -05:00
Adam a3eea40128 fix: select dialog hover 2025-09-24 15:08:58 -05:00
Adam 595e3d48f7 feat: fuzzy file open 2025-09-24 12:40:54 -05:00
Filip 89cb0f9a01 feat(app): added command palette (#2630)
Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
2025-09-24 11:05:15 -05:00
GitHub Action c394c696b2 ignore: update download stats 2025-09-24 2025-09-24 12:04:37 +00:00
opencode e28486d5cd release: v0.11.3 2025-09-24 03:43:46 +00:00
Dax Raad df7abea5fe update copilot auth 2025-09-23 23:36:27 -04:00
GitHub Action 6789cac430 chore: format code 2025-09-23 21:59:09 +00:00
Frank 4cd86236a1 zen: refund 2025-09-23 17:58:27 -04:00
GitHub Action e41a9b47fe chore: format code 2025-09-23 21:37:20 +00:00
Jay V 8e0e09e163 docs: add codex to zen 2025-09-23 17:36:40 -04:00
Jay V f0eb23c4d5 docs: edit 2025-09-23 17:34:52 -04:00
Jay V 7590ee788e docs: edits 2025-09-23 17:34:52 -04:00
Jay V 3bb2db5de3 docs: edit 2025-09-23 17:34:52 -04:00
Siddhant Choudhary e83e6c595c feat: output-format flag to stream json output (#2471)
Co-authored-by: Siddhant Choudhary <sid@treaps.com>
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-09-23 16:19:32 -05:00
opencode fde0faf6d8 release: v0.11.2 2025-09-23 21:03:59 +00:00
Dax Raad f8ba5e9572 fix codex errors 2025-09-23 16:56:40 -04:00
Dax Raad ef1f2943a5 fix: remove file existence check from LSP debug and format storage code 2025-09-23 16:49:57 -04:00
Alain Schlesser f9b415839b ignore: more reliable install script, handle non prettified json responses (#2745)
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-09-23 14:58:04 -05:00
Frank 815d6401c8 wip: remove 2025-09-23 14:21:39 -04:00
Frank 7231c6848e zen: update logged endpoints 2025-09-23 14:21:39 -04:00
Adam 3415dfda3b fix: open text files 2025-09-23 12:43:24 -05:00
David Hill f1f980c642 Merge branch 'dev' of https://github.com/sst/opencode into dev 2025-09-23 18:36:27 +01:00
David Hill 7c9616bf25 ignore: Copy update 2025-09-23 18:35:42 +01:00
David Hill 8be86f4b38 ignore: Footer update 2025-09-23 18:30:06 +01:00
Adam af202caf23 fix: exclude generated css file 2025-09-23 12:08:49 -05:00
GitHub Action 93cc1f11c9 chore: format code 2025-09-23 17:05:32 +00:00
Adam e20d12de23 fix: theme css format 2025-09-23 12:04:50 -05:00
GitHub Action ce87bc3592 chore: format code 2025-09-23 16:41:57 +00:00
Adam 0425aa413a wip: desktop file updates 2025-09-23 11:41:15 -05:00
Grégoire Paris c83dbb56dd docs: fix grammar mistake in lsp docs(#2744) 2025-09-23 08:12:46 -05:00
GitHub Action 52f88c0a88 ignore: update download stats 2025-09-23 2025-09-23 12:04:24 +00:00
Aiden Cline ed8369cd6b ignore: lsp debug file check (#2743) 2025-09-22 22:16:03 -05:00
Aiden Cline 0bff3e9c21 docs: github copilot model enable note (#2741) 2025-09-22 21:29:16 -05:00
Aiden Cline 5af4c7e066 fix: lsp extension undefined handle (#2739) 2025-09-22 21:14:55 -05:00
Joseph Hanson cf44950c18 docs: fix permissions link (#2738) 2025-09-22 20:28:54 -05:00
Adam Hosker 7232c702d6 docs: Add editor setup tip (#2638) 2025-09-22 16:01:27 -04:00
GitHub Action acd8819aca chore: format code 2025-09-22 19:59:29 +00:00
Jay V c55af547cf docs: edit tools doc 2025-09-22 15:58:48 -04:00
Aiden Cline e1265fb91f fix: enforce extensions requirement for custom lsp servers (#2734) 2025-09-22 11:45:47 -05:00
GitHub Action 98d111d551 ignore: update download stats 2025-09-22 2025-09-22 12:04:25 +00:00
Dax Raad b93a997ebd ci: bump 2025-09-22 01:47:28 -04:00
Dax Raad 7a32db138c ci: snapshot builds 2025-09-22 01:45:23 -04:00
iwauo dbfb523fd7 feat: add Java LSP server support (#2547)
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-09-21 23:55:15 -05:00
Aiden Cline 112cf7b59d fix: lsp spawn logic (#2723) 2025-09-21 11:25:47 -05:00
GitHub Action 375d7e1369 ignore: update download stats 2025-09-21 2025-09-21 12:04:06 +00:00
opencode 25d5454434 release: v0.11.1 2025-09-21 08:51:11 +00:00
Dax Raad a38b99b21c core: filter models without keys in opencode provider 2025-09-21 04:43:32 -04:00
opencode eb57274696 release: v0.11.0 2025-09-21 08:04:21 +00:00
GitHub Action 4f0f4f94b7 chore: format code 2025-09-21 04:23:40 +00:00
Frank 069baca7db wip: zen 2025-09-21 00:23:05 -04:00
Frank b1a72b006d wip: zen 2025-09-21 00:06:50 -04:00
Aiden Cline 1851bec769 ignore: lsp log (#2715) 2025-09-20 23:02:06 -05:00
opencode 31b4157b82 release: v0.10.4 2025-09-20 23:00:32 +00:00
Dax Raad da362e9460 turn back on compaction summaries 2025-09-20 18:52:30 -04:00
Osinachi Okpara 22e4625fb3 Enhance theme documentation with links (#2707)
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-09-20 11:25:12 -05:00
GitHub Action f68cbb7c6a ignore: update download stats 2025-09-20 2025-09-20 12:04:03 +00:00
Aiden Cline ca0b378090 fix: no payment method (#2706) 2025-09-20 04:15:44 -04:00
Jay V 59d536f010 docs: zen 2025-09-19 20:13:57 -04:00
opencode 227a797484 release: v0.10.3 2025-09-19 21:22:00 +00:00
GitHub Action 0903ca2e28 chore: format code 2025-09-19 18:18:56 +00:00
Frank 07c1d2492f zen: data share 2025-09-19 14:16:53 -04:00
Aiden Cline ad2b200f16 docs: fix bad docs (#2691) 2025-09-19 12:40:40 -05:00
GitHub Action ab6fef3e77 chore: format code 2025-09-19 17:29:44 +00:00
Jay V 0343083ab8 ignore: zen 2025-09-19 13:29:04 -04:00
Adam 86fa58ea41 wip: desktop progress 2025-09-19 10:53:49 -05:00
opencode 2fa657e875 release: v0.10.2 2025-09-19 15:18:11 +00:00
Adam b4cc733715 fix: remove grok msg 2025-09-19 09:59:47 -05:00
Adam 4755dba755 wip: desktop cleanup 2025-09-19 09:55:46 -05:00
Adam 24d56ba2ae wip: desktop cleanup 2025-09-19 09:42:39 -05:00
Adam a0a8bb7e0a wip: desktop visual tweaks 2025-09-19 09:38:10 -05:00
neriousy 8cf57b8130 chore: opencode favicon 2025-09-19 09:33:28 -05:00
GitHub Action 25c333f73a chore: format code 2025-09-19 14:32:55 +00:00
Adam 7bb5a17dcb chore: normalize theme hex 2025-09-19 09:32:19 -05:00
GitHub Action 0ae668a8ff chore: format code 2025-09-19 12:19:13 +00:00
Adam e175335790 wip: desktop work 2025-09-19 07:18:39 -05:00
Adam e6cb3f9f3b wip: desktop work 2025-09-19 07:18:39 -05:00
Adam 0dcc35c647 wip: desktop work 2025-09-19 07:18:39 -05:00
Adam 84ccad86dc wip: desktop starting state 2025-09-19 07:18:38 -05:00
GitHub Action abdf169190 ignore: update download stats 2025-09-19 2025-09-19 12:04:16 +00:00
GitHub Action 9e6234396b chore: format code 2025-09-19 10:14:30 +00:00
Dax Raad 3753c1e9cf ignore: fix 2025-09-19 06:13:45 -04:00
Dax Raad f1c1c942d1 ci: stuff 2025-09-19 06:10:27 -04:00
GitHub Action 26b0566811 chore: format code 2025-09-19 09:29:24 +00:00
Dax Raad 96caaf208e ci: stuff 2025-09-19 05:28:46 -04:00
GitHub Action b6cebc6b61 chore: format code 2025-09-19 09:12:20 +00:00
Dax Raad 41065c3353 ignore: rework bootstrap so server lazy starts it 2025-09-19 05:11:29 -04:00
opencode ec562bb9d8 release: v0.10.1 2025-09-19 05:15:32 +00:00
Dax Raad ce124c7a87 fix task tool ui disappearing once done 2025-09-19 01:09:52 -04:00
Aiden Cline ff95b17fc3 docs: subtask config option (#2682) 2025-09-18 17:52:23 -05:00
Aiden Cline 668c823ea8 docs: rm incorrect lsp mention (#2677) 2025-09-18 16:08:50 -05:00
opencode 9ec1ea01c7 release: v0.10.0 2025-09-18 20:51:03 +00:00
GitHub Action d7421e3e8a chore: format code 2025-09-18 14:59:48 +00:00
Frank fd354e7e52 wip: zen 2025-09-18 10:59:01 -04:00
GitHub Action 563d0b5606 ignore: update download stats 2025-09-18 2025-09-18 12:04:18 +00:00
Timo Clasen a5fb7bb215 fix(config): keybinds should not be required in config schema (#2669) 2025-09-18 06:30:44 -05:00
GitHub Action 6b606cb347 chore: format code 2025-09-18 09:43:35 +00:00
Dax Raad 5e290ca9e6 rework custom tools 2025-09-18 05:42:59 -04:00
Dax Raad b2117c41ee docs: add custom tools section to plugins documentation 2025-09-18 04:29:08 -04:00
Dax a3b5342f35 Plugin tool updates (#2670) 2025-09-18 04:26:57 -04:00
Dax bbe1d61875 support custom tools (#2668) 2025-09-18 03:58:21 -04:00
Frank 02f570e1b0 wip: zen 2025-09-18 01:36:54 -04:00
GitHub Action 5f7ce658ab chore: format code 2025-09-18 05:33:32 +00:00
Frank bd1403bbe8 wip: zen 2025-09-18 01:32:40 -04:00
GitHub Action 0632a48421 chore: format code 2025-09-18 03:39:57 +00:00
Jason Quense 1fcec281a6 fix: type exports in package.json for SDK package (#2654) 2025-09-17 23:39:26 -04:00
Julián Díaz b38fb570ae fix: add synthetic user prompt after session compaction (#2659)
Co-authored-by: Julián Díaz <git@jdiaz.io>
2025-09-17 23:27:37 -04:00
Frank 5db4541d83 Support GLM coding plan 2025-09-17 16:54:00 -04:00
Frank e3b840f4de wip: zen 2025-09-17 16:03:47 -04:00
Aiden Cline bbb912697d fix: only keep aborted messages if they have sufficient parts (#2651) 2025-09-17 14:24:53 -05:00
opencode 52694741bd release: v0.9.11 2025-09-17 16:29:48 +00:00
Aiden Cline 6bb3633751 Revert "fix: type 'reasoning' was provided without its required follo… (#2648) 2025-09-17 11:17:26 -05:00
opencode 50f14e7b22 release: v0.9.10 2025-09-17 14:54:25 +00:00
Timo Clasen 152d377191 fix(TUI): display correct branch name in git worktree (#2626) 2025-09-17 09:46:18 -05:00
Aiden Cline 07cc3671da fix: type 'reasoning' was provided without its required following item (#2633) 2025-09-17 09:45:13 -05:00
Aiden Cline a30a0c1a7a tweak: adjust title gen when using models like gpt-5-nano on non open… (#2646) 2025-09-17 08:39:34 -05:00
GitHub Action d8adbad56a ignore: update download stats 2025-09-17 2025-09-17 12:04:20 +00:00
opencode a9c12cffb8 release: v0.9.9 2025-09-17 07:40:40 +00:00
Dax Raad d9a54f52c3 ci: turborepo typecheck 2025-09-17 03:33:54 -04:00
Dax Raad bb61ae82cb add opencode attach command to connect to a remote opencode server 2025-09-17 03:30:25 -04:00
Dax Raad 79383f6082 only prune messages from more than 2 turns ago 2025-09-17 03:30:09 -04:00
opencode 2e912f0dae release: v0.9.8 2025-09-17 07:14:33 +00:00
Dax Raad 22fd365bf1 ignore: fix event type gen 2025-09-17 01:17:56 -04:00
opencode 1b84239e82 release: v0.9.7 2025-09-17 05:09:08 +00:00
Dax Raad ccae426f43 disable reading .env file automatically 2025-09-17 01:02:23 -04:00
GitHub Action c2f55b40da chore: format code 2025-09-16 23:53:59 +00:00
Jay V 1fc9c527f2 ignore: zen 2025-09-16 19:53:18 -04:00
Jay V c5d25653bc ignore: mobile styles zen 2025-09-16 19:39:36 -04:00
Jay V c993bd41cd ignore: zen 2025-09-16 19:39:36 -04:00
Frank dc84840401 wip: zen 2025-09-16 18:13:05 -04:00
Frank c8100a8d1b wip: zen 2025-09-16 17:49:39 -04:00
GitHub Action d6f4951936 chore: format code 2025-09-16 21:17:56 +00:00
Jay V 1025743379 ignore: zen 2025-09-16 17:17:17 -04:00
Jay V eca386996f ignore: zen 2025-09-16 17:17:17 -04:00
GitHub Action 448ad72f9b chore: format code 2025-09-16 20:17:16 +00:00
Jay V 9e81332c5f ignore: zen 2025-09-16 16:16:30 -04:00
opencode 528db70901 release: v0.9.6 2025-09-16 17:56:45 +00:00
Dax Raad 5d5023057b disable thinking for opencode zen and gpt-5 temporarily 2025-09-16 13:49:37 -04:00
GitHub Action 400c956457 chore: format code 2025-09-16 17:35:32 +00:00
Jay V 4d89c66b60 docs: zen 2025-09-16 13:26:49 -04:00
Frank 0ad4665b97 wip: zen 2025-09-16 09:01:13 -04:00
Aiden Cline ac6a96764f docs: remove dup section (#2629) 2025-09-16 07:30:29 -05:00
GitHub Action 2c62e76685 ignore: update download stats 2025-09-16 2025-09-16 12:04:17 +00:00
opencode 7dd96614b3 release: v0.9.5 2025-09-16 08:58:35 +00:00
Dax Raad 1d7fa7cca2 enable session pruning and allow disabling with OPENCODE_DISABLE_PRUNE 2025-09-16 04:53:17 -04:00
opencode 220e21c990 release: v0.9.4 2025-09-16 08:35:55 +00:00
Dax Raad 8fdc585174 fix crash when todo content is empty fixes #2622 2025-09-16 04:28:35 -04:00
Mani Sundararajan b09a909bfc fix(windows): force npm cmd shim generation and update install docs (#2558)
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: GitHub Action <action@github.com>
2025-09-16 03:40:19 -04:00
opencode 023edbd5ce release: v0.9.3 2025-09-16 07:16:25 +00:00
Dax Raad f4de6bef17 feat: enhance provider model mapping and reasoning capabilities
- Add npm package tracking to provider model mapping
- Implement special handling for opencode provider with reasoning
- Update provider options mapping to use npm package names
2025-09-16 03:10:17 -04:00
opencode 8050941095 release: v0.9.2 2025-09-16 04:29:00 +00:00
Dax 760c0fee65 feat: improve file watcher with chokidar and better ignore patterns (#2621)
Co-authored-by: GitHub Action <action@github.com>
2025-09-16 00:17:10 -04:00
Stephen Murray 7624f5839f fix: restore chat.message plugin hook (#2619) 2025-09-15 21:44:07 -05:00
GitHub Action 10cc8d90a1 chore: format code 2025-09-16 01:06:51 +00:00
Jay V 42b76259c9 docs: zen 2025-09-15 21:05:47 -04:00
Frank 7a658f1c5c wip: zen 2025-09-15 19:37:55 -04:00
Frank 600f9cd734 wip: zen 2025-09-15 19:26:46 -04:00
GitHub Action 563e7ee60e chore: format code 2025-09-15 23:19:50 +00:00
Jay V db6b7b06da ignore: zen 2025-09-15 19:19:10 -04:00
GitHub Action 59d621512d chore: format code 2025-09-15 23:03:41 +00:00
Jay V aff4806736 ignore: zen 2025-09-15 19:02:51 -04:00
Frank 14a310ba04 wip: zen 2025-09-15 18:47:04 -04:00
Frank 0daafe63cb wip: zen 2025-09-15 18:44:21 -04:00
opencode 82689a3478 release: v0.9.1 2025-09-15 22:31:44 +00:00
Dax Raad 79749d5f2c docs: zen 2025-09-15 18:21:03 -04:00
Frank 41207c9c08 wip: zen 2025-09-15 18:14:07 -04:00
Frank 991a41f3ba wip: zen 2025-09-15 17:37:07 -04:00
Frank 09134c49bc wip: zen 2025-09-15 17:07:48 -04:00
Frank 472ef832b7 wip: zen 2025-09-15 15:53:17 -04:00
GitHub Action e9669bd6a8 chore: format code 2025-09-15 19:39:00 +00:00
Jay V e645d2b9b2 docs: zen 2025-09-15 15:38:23 -04:00
Frank cd5ea5242e wip: zen 2025-09-15 15:21:06 -04:00
GitHub Action 42d822c550 chore: format code 2025-09-15 18:50:30 +00:00
Frank 8139842b68 wip: zen 2025-09-15 14:48:02 -04:00
Frank 6ffc97e576 wip: zen 2025-09-15 14:48:02 -04:00
GitHub Action 3707086de3 ignore: update download stats 2025-09-15 2025-09-15 12:04:17 +00:00
GitHub Action 36c58d7c04 chore: format code 2025-09-15 07:54:04 +00:00
Dax Raad 208fc70a4b ci: sync 2025-09-15 03:53:27 -04:00
Dax Raad 3e555038d7 ci: sync 2025-09-15 03:53:21 -04:00
GitHub Action 8d295049d1 chore: format code 2025-09-15 07:31:02 +00:00
Dax Raad 7e26967f1a ci: typecheck 2025-09-15 03:30:26 -04:00
Dax Raad c3f9ff756f ci: format 2025-09-15 03:28:53 -04:00
GitHub Action 40654a302d chore: format code 2025-09-15 07:28:34 +00:00
Dax 6a654abbc2 feat: add desktop/web app package (#2606)
Co-authored-by: adamdotdevin <2363879+adamdottv@users.noreply.github.com>
Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2025-09-15 03:28:08 -04:00
opencode ca65ae9e55 release: v0.9.0 2025-09-15 07:18:49 +00:00
Dax 0a4df97382 Upgrade to Zod v4 (#2605)
Co-authored-by: GitHub Action <action@github.com>
2025-09-15 03:12:07 -04:00
Aiden Cline ea5c182ba8 fix: visual token bug (#2603) 2025-09-14 21:23:52 -05:00
Aiden Cline f19b3e542f fix: reasoning metadata persistence (#2602) 2025-09-14 16:28:06 -05:00
Tommy D. Rossi 7ebbcbec17 log bash output when using opencode run (#2595) 2025-09-14 09:03:40 -05:00
Aiden Cline 740207016c tweak: make bash permissions key off of command pattern (#2592) 2025-09-14 09:01:57 -05:00
Kenn Costales 1d3c6c6257 fix: fix wrong tool references LS and Agent (#2466) 2025-09-14 08:53:50 -05:00
GitHub Action 6d2c6e2260 ignore: update download stats 2025-09-14 2025-09-14 12:03:54 +00:00
Dax Raad d2ef468743 ci: script 2025-09-14 02:07:58 -04:00
opencode 816b23b207 release: v0.8.0 2025-09-14 06:07:43 +00:00
Mani Sundararajan 0e6abf09f3 fix(dev): build tui with correct file ext for windows (#2590) 2025-09-14 01:59:25 -04:00
Aiden Cline 0e4a551e47 fix: token counting visual bug (#2587) 2025-09-13 19:46:24 -05:00
Aiden Cline 2abe97aee6 respect subagent in command, add subtask flag (#2569) 2025-09-13 12:47:18 -05:00
Aiden Cline d904257cc5 tweak: keep aborted msgs in context (#2583) 2025-09-13 12:25:30 -05:00
GitHub Action 121682a8fe ignore: update download stats 2025-09-13 2025-09-13 12:03:56 +00:00
Dax Raad 887d164fcd disable autocompact if context is 0 2025-09-13 05:59:18 -04:00
Dax Raad d3f5c567df add disable OPENCODE_DISABLE_AUTOCOMPACT 2025-09-13 05:55:04 -04:00
Dax Raad d61f529c34 ignore: fix 2025-09-13 05:53:03 -04:00
Dax 7d8d63faff Session management and prompt handling improvements (#2577)
Co-authored-by: GitHub Action <action@github.com>
2025-09-13 05:46:14 -04:00
opencode d2cf3b231c release: v0.7.9 2025-09-13 05:29:37 +00:00
Dax Raad 22c4307fec nudge llm to continue properly after compaction 2025-09-13 01:23:54 -04:00
Tommy D. Rossi fd7c62e697 fix: ShellError: exit code 1 errors (#2568)
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-09-13 00:06:07 -05:00
Nicholas Hamilton e087003f3f docs: typo in web agents.mdx (#2574) 2025-09-12 23:26:52 -05:00
Trillium Smith ccbf9cd8cd docs: add tip block for finding available models (#2501)
Co-authored-by: GitHub Action <action@github.com>
2025-09-12 21:22:54 -04:00
Aiden Cline 2c0323e79e fix: make permission always behavior match expectation (#2573) 2025-09-12 18:59:38 -05:00
Stephen Murray 74bea03e67 fix: await cleanupRevert() to prevent dupe msgs after undo (#2572) 2025-09-12 18:42:39 -05:00
Dax Raad 0688a6c486 wip: zen 2025-09-12 14:53:00 -04:00
GitHub Action a7dfdba562 chore: format code 2025-09-12 18:46:43 +00:00
Dax Raad 37755ccbbd wip: zen 2025-09-12 14:46:08 -04:00
GitHub Action cadca5af9d chore: format code 2025-09-12 18:33:14 +00:00
Jay V e544cbb8d0 ignore: zen 2025-09-12 14:32:43 -04:00
Frank 45e0df3fa7 wip: zen 2025-09-12 14:22:42 -04:00
opencode 2fc8695f70 release: v0.7.8 2025-09-12 18:09:55 +00:00
Dax Raad 680c1367ea temporarily disable midstream compaction 2025-09-12 14:00:54 -04:00
Dax Raad 830663b340 ci: exclude production branch from format workflow 2025-09-12 13:41:38 -04:00
opencode 4adb22487d release: v0.7.7
Format / format (push) Waiting to run
2025-09-12 17:28:35 +00:00
Dax Raad f592e64ac6 undo session pruning 2025-09-12 13:20:13 -04:00
GitHub Action 3e75b5e930 chore: format code 2025-09-12 16:19:09 +00:00
Frank b877c7ad3f wip: zen 2025-09-12 12:18:32 -04:00
Frank 2f92f38fcf Merge branch 'production' into dev 2025-09-12 12:04:27 -04:00
GitHub Action a2f6e6ab16 chore: format code 2025-09-12 15:57:50 +00:00
Frank 5d54d19d07 wip: zen 2025-09-12 11:57:14 -04:00
Frank 9bd09c7e74 wip: zen 2025-09-12 11:57:14 -04:00
GitHub Action 9f62c9347f ignore: update download stats 2025-09-12 2025-09-12 12:04:14 +00:00
Dax Raad 5d22ea0330 ignore: internal 2025-09-12 10:45:44 +00:00
opencode 3fac32ef42 release: v0.7.6
Format / format (push) Waiting to run
2025-09-12 10:45:44 +00:00
Dax Raad b52a1054eb add microcompact 2025-09-12 06:38:47 -04:00
opencode 784c8c443e release: v0.7.5
Format / format (push) Waiting to run
2025-09-12 10:25:57 +00:00
opencode 4c8f81618e release: v0.7.4
Format / format (push) Waiting to run
2025-09-12 10:08:33 +00:00
Dax Raad 501c9c598d fix compaction issues 2025-09-12 06:01:11 -04:00
GitHub Action 124be7c2b5 chore: format code 2025-09-11 22:34:21 +00:00
GitHub Action af4e99ac04 chore: format code 2025-09-11 22:30:52 +00:00
Frank 10dee84a48 wip: zen 2025-09-11 18:30:13 -04:00
Dax Raad d681989faa wip: zen 2025-09-11 18:20:37 -04:00
opencode b76ec4d44f release: v0.7.3
Format / format (push) Waiting to run
2025-09-11 21:38:17 +00:00
Frank bd47dfd884 Merge branch 'production' into dev 2025-09-11 17:28:51 -04:00
GitHub Action 7972ecdc45 chore: format code 2025-09-11 21:22:56 +00:00
Frank ab8f3b1109 wip: zen 2025-09-11 17:22:05 -04:00
Dax Raad f21a63c1d4 properly support model level npm definition 2025-09-11 16:22:44 -04:00
Chris Covington 599233a52c feat: Add an experimental option to disable paste summaries (#2552)
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-09-11 14:21:08 -05:00
Aiden Cline b06068c101 fix: command being passed as arg when no args present (#2553) 2025-09-11 13:03:12 -05:00
opencode ed6964ab87 release: v0.7.2
Format / format (push) Waiting to run
2025-09-11 17:02:59 +00:00
Dax Raad b2e2d36010 reduce LSP verbosity 2025-09-11 12:54:12 -04:00
Dax Raad 7b91d612f6 remove block anchor edit 2025-09-11 12:53:10 -04:00
GitHub Action a853ef50ea ignore: update download stats 2025-09-11 2025-09-11 12:04:26 +00:00
Dax Raad 20b28c8265 ignore: compacting 2025-09-11 02:31:28 -04:00
Dax Raad 785feb29a7 compaction improvements 2025-09-11 02:22:51 -04:00
GitHub Action 65ca0b73c2 chore: format code 2025-09-11 05:33:59 +00:00
Frank d3367a24c9 wip: zen 2025-09-11 01:33:23 -04:00
Frank d9cd7e1808 wip: zen 2025-09-11 01:32:06 -04:00
GitHub Action ff626cd435 chore: format code 2025-09-11 04:00:17 +00:00
GitHub Action 08ccb6f17a chore: format code 2025-09-11 03:59:39 +00:00
Jay V 2912a9cdc4 ignore: zen 2025-09-10 17:59:03 -10:00
Jay V f7ca56ae63 docs: lander 2025-09-10 16:42:32 -10:00
Jay V fc3c1f08cd docs: add twitter 2025-09-10 11:47:41 -10:00
Frank ccd73e18cd wip: zen 2025-09-10 17:39:28 -04:00
Emmanuel LOUISY-GABRIEL 4dfb9cce22 Update providers.mdx because of small typo (#2539) 2025-09-10 15:49:25 -05:00
Aiden Cline 89ff5fa1dc resolve nested commands (#2537) 2025-09-10 14:05:26 -05:00
Aiden Cline 16eac2dea6 fix: handle @dir in command (#2533) 2025-09-10 13:27:44 -05:00
opencode 518f449396 release: v0.7.1
Format / format (push) Waiting to run
2025-09-10 15:40:31 +00:00
Dax Raad cdac0554e3 fix issue with flags being parsed incorrectly 2025-09-10 11:34:39 -04:00
GitHub Action ffeb38106c ignore: update download stats 2025-09-10 2025-09-10 12:04:18 +00:00
opencode 3fa07f6050 release: v0.7.0
Format / format (push) Waiting to run
2025-09-10 08:42:45 +00:00
Dax Raad 7113bf6c1e ci: stuff 2025-09-10 04:35:49 -04:00
Dax Raad e53ec49e15 ci: stuff 2025-09-10 04:27:23 -04:00
Dax Raad c79dbd0c4e ci: bump version 2025-09-10 04:23:57 -04:00
GitHub Action 104459e013 chore: format code 2025-09-10 07:40:01 +00:00
Dax Raad c484ebf5a4 upgrade to latest bun 2025-09-10 03:36:42 -04:00
Dax Raad 1c314492a3 wip: ignore 2025-09-10 03:13:42 -04:00
Aiden Cline 9f40976a96 tweak: wrap build-switch w/ system-reminder (#2525) 2025-09-09 23:57:13 -05:00
GitHub Action 9a7e5a732a chore: format code 2025-09-10 03:49:07 +00:00
Dax Raad 31c240fcca ci: fix 2025-09-09 23:48:35 -04:00
Dax Raad 4533ba053a ci: format 2025-09-09 23:47:47 -04:00
Dax Raad 972a36dba1 ci: format 2025-09-09 23:44:04 -04:00
Dax Raad e3bf324ea9 ci: format 2025-09-09 23:44:04 -04:00
opencode e9c9700ed9 release: v0.6.10 2025-09-10 03:32:47 +00:00
Dax Raad 1d190a3a94 repair tool calls when casing is wrong 2025-09-09 23:25:27 -04:00
opencode 21dd955c2f release: v0.6.9 2025-09-09 21:17:41 +00:00
Frank adf0811abb wip: zen 2025-09-09 16:40:12 -04:00
Frank f9c570cdfc wip: zen 2025-09-09 16:32:56 -04:00
Frank b8a9794727 wip: zen 2025-09-09 16:15:35 -04:00
Frank 25a1b344eb wip: zen 2025-09-09 15:47:28 -04:00
madflow e275de0fcb feat: svelte lsp (#2508) 2025-09-09 13:59:58 -05:00
Aiden Cline ddb9d6626c fix: exit code being non zero when using run cmd (#2523) 2025-09-09 12:00:55 -05:00
GitHub Action e02f2d17c1 ignore: update download stats 2025-09-09 2025-09-09 12:04:32 +00:00
Frank 4a9da4c3da wip: zen 2025-09-09 05:42:15 -04:00
opencode b9c2207813 release: v0.6.8 2025-09-09 07:40:23 +00:00
Frank ed3cd6f1cd Remove debug logging 2025-09-09 03:35:09 -04:00
opencode da236da9da release: v0.6.7 2025-09-09 07:23:01 +00:00
Frank 1d9cc05887 Hide experimental models 2025-09-09 03:16:44 -04:00
Frank 993c3685ca wip: zen 2025-09-09 02:44:36 -04:00
Aiden Cline 90111a36b6 remove edit tool from plan agent (#2505) 2025-09-08 22:00:14 -05:00
Frank 11d35600d8 Merge branch 'production' into dev 2025-09-08 16:37:38 -04:00
Zack Jackson 37893ed24c feat: add dynamic tool registration for plugins and external services (#2420) 2025-09-08 16:25:04 -04:00
opencode 0b180bf1ca release: v0.6.6 2025-09-08 20:20:35 +00:00
Mani Sundararajan 55cfad5282 feat: make npm package install work on windows (#2419) 2025-09-08 16:14:18 -04:00
Frank 228ca510a3 wip: zen 2025-09-08 15:57:29 -04:00
Frank a315caa291 wip: zen 2025-09-08 15:51:01 -04:00
Frank 51a8db019b Zen: telemetry 2025-09-08 15:46:59 -04:00
Aiden Cline b585e4f92d tweak: reenable todowrite & todoread for qwen models (#2499) 2025-09-08 13:21:16 -05:00
Douglas Dennis 2786177c76 fix: aws bedrock add check for govcloud (#2495) 2025-09-08 11:54:06 -05:00
GitHub Action 1bad3b36d7 ignore: update download stats 2025-09-08 2025-09-08 12:04:58 +00:00
Aiden Cline 50c38c31a3 fix: silent error if bad flag was passed (#2486) 2025-09-07 23:14:38 -05:00
Aiden Cline c05adad02e fix: shell invocations are dropped if last interaction was revert (#2485) 2025-09-07 21:45:13 -05:00
Aiden Cline ffe1cfdba9 fix: dont paste collapse if in bash mode (#2482) 2025-09-07 20:24:49 -05:00
opencode 4b15e464e1 release: v0.6.5 2025-09-07 19:44:44 +00:00
Ytzhak 9d167eda41 fix: max output tokens when setting budget thinking tokens (#2056)
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-09-07 13:15:53 -05:00
GitHub Action 67af3e1046 ignore: update download stats 2025-09-07 2025-09-07 12:03:51 +00:00
Aiden Cline 51a33e5c37 fix: title gen w/ gpt-5-nano (#2473) 2025-09-06 22:50:16 -05:00
Aiden Cline 77293db088 fix: title not generated if first msg is shell invocation (#2451) 2025-09-06 09:47:42 -05:00
GitHub Action 82856b770e ignore: update download stats 2025-09-06 2025-09-06 12:03:41 +00:00
Aiden Cline 02bd730bdf fix: command model selection (#2448) 2025-09-05 20:54:39 -05:00
Aiden Cline c63ab8e483 fix: default to last used model (#2443) 2025-09-05 17:25:25 -05:00
Adam 6e7fed27df fix: file read response 2025-09-05 15:58:56 -05:00
spoons-and-mirrors 52dea9cb75 tweak(edit): separate edit tool error message with clearer guidance to avoid llm doom editing loop (#2051) 2025-09-05 12:36:13 -04:00
GitHub Action 661ee30af6 ignore: update download stats 2025-09-05 2025-09-05 12:04:16 +00:00
Jay V 61363d6e66 docs: fix lander 2025-09-04 17:44:32 -10:00
Michał Olender ab8f5ecbe7 Update index.tsx (#2423) 2025-09-04 17:44:26 -10:00
Aiden Cline 5ab2b8c70f fix: webfetch prompt mistake (#2424) 2025-09-04 13:35:25 -05:00
Adam ce7bc4d770 fix: better file/content return 2025-09-04 12:39:49 -05:00
GitHub Action d059236d98 ignore: update download stats 2025-09-04 2025-09-04 12:04:06 +00:00
Adam 2f0d8cb0e5 fix: worktree file/content never includes patch 2025-09-04 06:10:07 -05:00
Jay V 6fa3aef36e ignore: 404 2025-09-04 01:39:54 -07:00
Jay V 7f126e3aab docs: fix 2025-09-04 01:03:23 -07:00
Jay V 18f31e4263 docs: handle base path 2025-09-04 00:53:45 -07:00
Jay V 2c18e8181f ignore: zen 2025-09-04 00:17:06 -07:00
Zack Jackson d503ff2993 feat: add createOpencodeTui() function to SDK for programmatic TUI launching (#2410) 2025-09-04 02:49:44 -04:00
Aiden Cline a3ad73b616 fix: file fuzzy search (#2409) 2025-09-03 23:20:16 -05:00
Jay V aa7088ae6e ignore: mobile styles 2025-09-03 19:33:01 -07:00
Jay V d44536d097 ignore: lander 2025-09-03 19:05:49 -07:00
Jay V 240412eab4 docs: lander 2025-09-03 18:30:04 -07:00
Jay V 6ea88d4685 ignore: cloud 2025-09-03 17:21:46 -07:00
Jay V 79a3146065 docs: link 2025-09-03 17:12:51 -07:00
Jay V 891b885328 ignore: zen 2025-09-03 15:53:31 -07:00
Frank 0887902406 wip console 2025-09-03 15:57:41 -04:00
Frank e3c7e5ab50 wip console 2025-09-03 15:35:46 -04:00
Dax Raad 7442703063 wip: cloud 2025-09-03 14:57:02 -04:00
Dax Raad 36be710d37 ignore: opencode auth stuff 2025-09-03 14:43:50 -04:00
Dax Raad ee9c67c05e wip: email 2025-09-03 14:32:05 -04:00
Dax Raad 9d1a1591de wip: fix logout 2025-09-03 14:24:37 -04:00
Frank 618a8ac0bf wip console 2025-09-03 14:09:39 -04:00
Frank a15f0f6930 wip console 2025-09-03 14:07:57 -04:00
Dax Raad dea706f4cf wip: logout 2025-09-03 14:07:23 -04:00
Dax Raad 15589bd963 wip: css 2025-09-03 14:05:10 -04:00
Dax Raad 6bb5b71e18 wip: css hack 2025-09-03 13:58:08 -04:00
Dax Raad e971d10944 wip: cloud 2025-09-03 13:58:08 -04:00
Dax Raad 0fc8a6dbc5 wip: cloud 2025-09-03 13:58:08 -04:00
Frank 67d0db8f66 wip cloud smart 2025-09-03 13:52:01 -04:00
Frank 759a31f675 script package 2025-09-03 13:43:32 -04:00
Dax Raad d3e9953080 wip: cloud 2025-09-03 13:17:32 -04:00
Dax Raad 9c8fe9d526 wip: make less shit 2025-09-03 13:10:57 -04:00
Dax Raad f61bcf330e wip: cloud 2025-09-03 12:32:03 -04:00
Frank b3b97b1d74 wip console 2025-09-03 11:50:18 -04:00
Frank 5fbab7f9c5 wip console 2025-09-03 11:40:59 -04:00
Frank 237a02cb76 wip console 2025-09-03 11:31:16 -04:00
Frank 89a1845ea3 wip: generate config.json 2025-09-03 11:24:13 -04:00
Jay V d13257a564 ignore: zen 2025-09-03 11:16:49 -04:00
Jay V 1a41dbc1a6 ignore: zen 2025-09-03 11:10:07 -04:00
Jay V 2626085c78 docs: edits 2025-09-03 11:05:43 -04:00
opencode ee04ca8155 release: v0.6.4 2025-09-03 13:31:11 +00:00
Frank d9e726838a wip console 2025-09-03 09:24:23 -04:00
GitHub Action 1b5d2c6696 ignore: update download stats 2025-09-03 2025-09-03 12:04:06 +00:00
Frank e8b1b4f63b wip console 2025-09-03 06:53:30 -04:00
Frank 1d131b16f7 wip: console 2025-09-03 06:37:40 -04:00
Frank f0719f51b4 wip: console 2025-09-03 06:27:53 -04:00
Frank c784fa6fce wip: console 2025-09-03 06:22:44 -04:00
Frank 8265c2ee31 wip: console 2025-09-03 06:15:08 -04:00
Frank 4f9dffc44e wip: console 2025-09-03 06:12:17 -04:00
Dax Raad 5ff4ceff6d wip: console 2025-09-03 01:33:49 -04:00
Brendan Allan 6cfa8ead44 Patch Start to preload route css in SSR (#2389) 2025-09-03 01:28:34 -04:00
Dax Raad 2777e1dd07 wip: zen 2025-09-02 23:56:10 -04:00
Dax Raad caa93616d4 wip: zen 2025-09-02 23:30:48 -04:00
Frank 75ea8738c8 wip cloud 2025-09-02 23:28:54 -04:00
Dax Raad 3eb235fc1a docs: remove remaining directory query param mentions from SDK docs 2025-09-02 22:25:32 -04:00
Dax Raad d1ca6624f0 docs: remove directory query param mentions from SDK docs 2025-09-02 22:25:32 -04:00
Dax Raad 57c8d110e6 docs: fix SDK usage to use path/query/body, correct return types, and update examples 2025-09-02 22:25:32 -04:00
Aiden Cline 8c0076d57d fix: more durable @ references for commands (#2386) 2025-09-02 21:24:56 -05:00
Jay V 7d396b5961 docs: zen 2025-09-02 21:29:03 -04:00
Jay V 2f5af3850d ignore: adding public files 2025-09-02 21:25:09 -04:00
Frank 0b05d1e5da generate api key 2025-09-02 20:38:36 -04:00
Frank 63b55ebb0b wip: cloud 2025-09-02 20:01:13 -04:00
Dax Raad ff11b57fb4 ci: ignore 2025-09-02 19:32:21 -04:00
Dax Raad a5bfd9d2be wip: zen 2025-09-02 18:00:48 -04:00
Jay V 7ad846a2b0 ignore: zen 2025-09-02 17:30:51 -04:00
Jay V 27f3987958 ignore: zen 2025-09-02 17:28:35 -04:00
Jay V 25614a9cac ignore: cloud lander 2025-09-02 17:28:35 -04:00
Dax Raad 73cedc7225 wip: zen 2025-09-02 16:38:50 -04:00
Dax Raad 846959544c docs: simplify config example to show only model 2025-09-02 16:38:50 -04:00
Dax Raad 34763d8f5b docs: clarify config behavior and remove theme example 2025-09-02 16:38:50 -04:00
Dax Raad b6f9112de1 docs: add config example to SDK server creation 2025-09-02 16:38:50 -04:00
Dax Raad 2f726087fb support OPENCODE_CONFIG_CONTENT 2025-09-02 16:38:50 -04:00
Aiden Cline a024ba1645 tweak: update ls tool to use rg (#2367) 2025-09-02 10:40:20 -05:00
Yuta URANO 2b8cfe90be docs: update log level configuration in troubleshooting guide (#2374) 2025-09-02 10:31:04 -05:00
OpeOginni bf02c6a265 fix: local subdirectory subagents not being picked up (#2376) 2025-09-02 09:46:00 -05:00
GitHub Action c6858f5531 ignore: update download stats 2025-09-02 2025-09-02 12:04:59 +00:00
Adam ae66b4411c fix: file.list relative to root 2025-09-02 06:20:08 -05:00
Dax Raad a82e23f3ac wip: typechecking 2025-09-02 03:18:30 -04:00
Dax Raad 3d338e20d6 wip: cloud 2025-09-02 03:18:30 -04:00
Adam Spiers 8bef2c7538 make @file references in custom slash commands more robust (#2203)
Co-authored-by: Adam Spiers <opencode@adamspiers.org>
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-09-01 21:14:27 -05:00
opencode c245bfc925 release: v0.6.3 2025-09-02 01:52:01 +00:00
Dax Raad 041b37b64f switch gpt-5 to default to codex prompt + high reasoning 2025-09-01 21:46:03 -04:00
opencode 4c81d9917c release: v0.6.2 2025-09-02 01:03:43 +00:00
Aiden Cline 5dfa61f722 fix: ensure opencode still works if no commits present (#2363) 2025-09-01 20:57:14 -04:00
Aiden Cline 6e911f5f2e fix: ensure enabled lsps are all logged (#2364) 2025-09-01 17:43:31 -05:00
opencode 744f664a1d release: v0.6.1 2025-09-01 22:07:53 +00:00
Dax Raad 1e6134f5c9 catch migration failures 2025-09-01 18:00:40 -04:00
opencode 0794954467 release: v0.6.0 2025-09-01 21:43:13 +00:00
Dax Raad 4fa6df14ae docs: sdk 2025-09-01 17:35:52 -04:00
Aiden Cline bac6f3918d fix: tui attachment bound (#2361) 2025-09-01 16:33:36 -05:00
Jay V 5fd349d369 docs: update email 2025-09-01 17:30:32 -04:00
Dax aea78046d0 Refactor to support multiple instances inside single opencode process (#2360)
This release has a bunch of minor breaking changes if you are using opencode plugins or sdk

1. storage events have been removed (we might bring this back but had some issues)
2. concept of `app` is gone - there is a new concept called `project` and endpoints to list projects and get the current project
3. plugin receives `directory` which is cwd and `worktree` which is where the root of the project is if it's a git repo
4. the session.chat function has been renamed to session.prompt in sdk. it no longer requires model to be passed in (model is now an object)
5. every endpoint takes an optional `directory` parameter to operate as though opencode is running in that directory
2025-09-01 17:15:49 -04:00
Aiden Cline cb5bf46f18 add --command to opencode run (#2348) 2025-09-01 14:19:18 -05:00
Dax Raad 42722933ef wip: cloud 2025-09-01 11:53:43 -04:00
Dax Raad d82099fff0 wip: cloud 2025-09-01 11:47:58 -04:00
GitHub Action 90d8f2fe5d ignore: update download stats 2025-09-01 2025-09-01 12:04:32 +00:00
Dax Raad 163385843c wip: cloud 2025-09-01 04:03:07 -04:00
Dax Raad cd41d154ef wip: cloud 2025-09-01 03:55:48 -04:00
Dax Raad 42dc32cac6 wip: cloud 2025-09-01 03:53:49 -04:00
Dax Raad 9532546da0 wip: cloud 2025-09-01 03:51:45 -04:00
Dax Raad ac90473d3f wip: sync 2025-09-01 03:15:38 -04:00
Dax Raad 40fc416789 wip: cloud 2025-09-01 03:13:05 -04:00
Dax Raad f8ce2a82a1 wip: cloud 2025-09-01 03:10:40 -04:00
Dax Raad 0b6affe1bf wip: cloud 2025-09-01 03:04:49 -04:00
Dax Raad 1c8f9b7500 wip: cloud 2025-09-01 03:04:07 -04:00
Dax Raad 85dd3c4abc wip: cloud 2025-09-01 02:57:47 -04:00
Dax Raad 48d835599e wip: cloud 2025-09-01 02:55:10 -04:00
Dax Raad ba96940ec6 wip: cloud 2025-09-01 02:28:21 -04:00
Dax Raad 88dbbc0b97 wip: cloud 2025-09-01 02:21:36 -04:00
Régis Blanc a45f0febbf fix: ensure gopls lsp id matches docs (#2344) 2025-08-31 21:52:08 -05:00
Aiden Cline 6df5b8dc64 ignore: better error logging (#2346) 2025-08-31 17:11:04 -05:00
Beshoy Girgis bf77aa6acd feat: Allow provider timeout override (#1982) 2025-08-31 14:06:02 -04:00
Aiden Cline f7e413fe95 fix: ensure shell cmds can be properly aborted (#2339) 2025-08-31 12:48:30 -05:00
Aiden Cline ed9a2aa2df fix: adjust title generation prompt to prevent direct response instead of title gen (#2338) 2025-08-31 11:01:19 -05:00
GitHub Action 26b3be7c6b ignore: update download stats 2025-08-31 2025-08-31 12:04:06 +00:00
Andre van Tonder 1e2c48b3ad fix: resolve virtual envs for python LSP (#2155)
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-08-30 23:53:03 -05:00
Aiden Cline 174177c304 fix: ensure command uses currently selected model (#2336) 2025-08-30 15:41:06 -05:00
Aiden Cline b28229a645 add support for lsp workspace/didChangeConfiguration (#2334) 2025-08-30 14:49:13 -05:00
Jay V 9784619443 ignore: cloud 2025-08-30 15:28:35 -04:00
Jay V 1ec283a00e ignore: cloud styles 2025-08-30 15:27:46 -04:00
Dax Raad 35101a30a5 wip: cloud 2025-08-30 15:20:51 -04:00
Aiden Cline 9d9179a021 fix: resolve [pasted lines] when passing paste as arguments for command (#2333) 2025-08-30 10:56:00 -05:00
Aiden Cline 4b2c8c1528 tweak: ensure run command doesn't send request if no prompt present (#2332) 2025-08-30 10:39:28 -05:00
Roderik van der Veer d4669a33fc fix: change command selection to prefer exact matches over fuzzy sear… (#2314) 2025-08-30 09:44:27 -05:00
GitHub Action d7dd7b8b84 ignore: update download stats 2025-08-30 2025-08-30 12:03:53 +00:00
Anton edfc1c315a Use a single rust LSP server instance for entire cargo workspace (#2292) 2025-08-30 06:00:39 +00:00
opencode 4af5cf9223 release: v0.5.29 2025-08-30 06:00:39 +00:00
Dax Raad 901c85cef7 ignore: sync 2025-08-30 01:36:25 -04:00
Dax Raad d609d57dc4 ignore: fix stuff 2025-08-30 01:19:03 -04:00
Dax Raad 1caed3b7f1 ignore: fix dev remote 2025-08-30 01:06:48 -04:00
Dax Raad 5a8b0e455b ignore: cloud resource 2025-08-30 00:58:22 -04:00
Frank 34841b7c9c wip: cloud 2025-08-29 23:32:17 -04:00
Frank 12eadc6103 wip cloud 2025-08-29 23:02:27 -04:00
Aiden Cline 8d51ab434f fix: mcp tool not triggering hooks (#2320) 2025-08-29 21:51:06 -05:00
Jay V bad27eb6e0 ignore: cloud keys section 2025-08-29 20:04:57 -04:00
Dax Raad 22df2a2955 ignore: create key for new workspace 2025-08-29 19:56:29 -04:00
Frank 3323f9367a wip: cloud 2025-08-29 19:45:17 -04:00
Frank 70cc880e3f wip: cloud 2025-08-29 19:34:58 -04:00
Jay V a9437c7fda ignore: cloud balance section 2025-08-29 19:20:18 -04:00
Jay V 71be62f871 ignore: cloud payment history 2025-08-29 19:20:18 -04:00
Jay V ec9705b8cf ignore: cloud usage history 2025-08-29 19:20:18 -04:00
Jay V b75e116d88 ignore: cloud progress 2025-08-29 19:20:18 -04:00
Parbez f36dbee990 Fix code block formatting in sdk.mdx (#2312) 2025-08-29 14:29:18 -05:00
Jay V a0e88242bb ignore: cloud 2025-08-29 12:48:01 -04:00
Frank 404859963a Update sst 2025-08-29 12:26:03 -04:00
Aiden Cline ede8b55c9f fix: lsp debug cmd log (#2310) 2025-08-29 11:11:26 -05:00
Dax Raad 8714df56e8 ignore: cloud solid fixes 2025-08-29 11:58:17 -04:00
Aiden Cline dc5c71b365 ignore: add error log for title gen failures (#2309) 2025-08-29 10:53:58 -05:00
Aiden Cline 948ce1a0bf fix: add additional encouragement for title gen (#2298) 2025-08-29 09:47:08 -05:00
GitHub Action e023a13bc7 ignore: update download stats 2025-08-29 2025-08-29 12:04:20 +00:00
Aiden Cline a250fb17fc tui: show actual error if command fails (#2296) 2025-08-28 18:42:55 -05:00
Adam 0476ae36ef chore: remove unused dep 2025-08-28 18:16:38 -05:00
Adam 5873046b0c chore: update gitignore 2025-08-28 18:16:05 -05:00
Netanel Draiman e0db411788 fix: replace isomorphic-git status with direct git diff for worktree support (#1706)
Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
2025-08-28 18:15:26 -05:00
Aiden Cline 98e00fbf47 allow slash commands to resolve ~/ references (#2295) 2025-08-28 17:31:03 -05:00
Jay V 00ff7303e3 ignore: cloud styles 2025-08-28 18:13:51 -04:00
Frank d76fe99dc0 wip cloud 2025-08-28 17:52:20 -04:00
Jay V ebfb9b7a03 ignore: cloud 2025-08-28 17:37:48 -04:00
Dax Raad b355b01906 ignore: cloud 2025-08-28 17:35:54 -04:00
Dax Raad 3ea92d4212 ignore: cloud 2025-08-28 17:33:52 -04:00
Jay V 5fc278a911 ignore: cloud 2025-08-28 17:17:00 -04:00
Jay V e4682db8d8 ignore: cloud 2025-08-28 17:10:41 -04:00
Jay V a8ff90141f ignore: cloud 2025-08-28 17:06:37 -04:00
Frank 94eb1328bf wip cloud 2025-08-28 17:05:51 -04:00
Frank 4bc0e04687 wip cloud 2025-08-28 16:44:55 -04:00
Jay V 5920b616d5 ignore: cloud 2025-08-28 16:29:21 -04:00
Jay V c9dd7c384c ignore: cloud 2025-08-28 16:21:09 -04:00
Jay V 1935ba7774 ignore: cloud styles 2025-08-28 16:21:09 -04:00
Adam 6e8f321d68 feat: home dir in app info 2025-08-28 14:34:20 -05:00
Jay V bd173ce4f7 ignore: cloud 2025-08-28 14:18:37 -04:00
Jay V ae5c3ad98a ignore: cloud 2025-08-28 14:12:31 -04:00
Dax Raad 0fe6be6a13 ignore: cloud 2025-08-28 14:09:51 -04:00
Jakub Kopecký 1db898ceb6 fix: mcp client name (#2289) 2025-08-28 12:48:29 -05:00
Ethan Shea 20e5262325 Vercel AI Gateway key deeplinks into the dashboard (#2287) 2025-08-28 11:06:45 -05:00
Aiden Cline b69264990b fix: tui not showing err toasts (#2290) 2025-08-28 10:55:47 -05:00
Adam 4746d88a53 feat: include ignored files 2025-08-28 10:49:45 -05:00
GitHub Action 00ab315cdd ignore: update download stats 2025-08-28 2025-08-28 12:04:29 +00:00
Dax Raad 5ab3048c7d ignore: cloud 2025-08-27 21:49:39 -04:00
Dax Raad d025ee042a ignore: cloud 2025-08-27 21:49:04 -04:00
Dax Raad bbaade5702 ignore: cloud 2025-08-27 21:47:45 -04:00
Jay V 87080c426a ignore: cloud 2025-08-27 19:36:44 -04:00
Aiden Cline 8dd86d89ff docs: add copy button to user messages too (#2285) 2025-08-27 18:14:27 -05:00
Aiden Cline b067382147 add synthetic user message before bash execution (when using !) (#2283) 2025-08-27 17:41:24 -05:00
Jay V 9bed0f92d5 ignore: cloud 2025-08-27 17:53:15 -04:00
Aiden Cline 23e3f10235 fix: ensure / commands dont try to resolve @ references from cmd outputs (#2282) 2025-08-27 15:59:33 -05:00
Adam 8e22caf277 feat: file list api 2025-08-27 15:28:03 -05:00
Jay V 420df81ece ignore: cloud 2025-08-27 16:02:32 -04:00
Aiden Cline d11214b0f4 docs: fix client.event.subscribe example (#2280) 2025-08-27 11:42:09 -05:00
Dax Raad f1077d86ed sdk update 2025-08-27 12:18:09 -04:00
Aiden Cline 1a53281ef7 docs: document anthropic thinking budgets (#2243) 2025-08-27 09:41:51 -05:00
GitHub Action 02764e089d ignore: update download stats 2025-08-27 2025-08-27 12:04:25 +00:00
spoons-and-mirrors 287c079a97 fix: shimmer cpu cost (#2084) 2025-08-27 06:18:26 -05:00
Jay V fd7389777f docs: edit 2025-08-26 17:30:43 -04:00
Stibbs 9650c18caf docs: mcp access mgmt instructions (#2087) 2025-08-26 17:27:44 -04:00
opencode 385ef8d0ab release: v0.5.28 2025-08-26 20:23:34 +00:00
Frank 3246645642 Revert "fix(tui): too early"
This reverts commit b88b0e0eb5.
2025-08-26 16:13:16 -04:00
Jay V df2db05030 docs: edit commands 2025-08-26 16:10:53 -04:00
Jay V 117bfa6083 docs: updating config schema 2025-08-26 16:10:53 -04:00
Jay V 642042e77c docs: adding new provider 2025-08-26 16:10:53 -04:00
Aiden Cline c1fdcb458c fix: bash tool description (#2260) 2025-08-26 13:42:01 -05:00
GitHub Action 4501d9bad6 ignore: update download stats 2025-08-26 2025-08-26 12:04:26 +00:00
Aiden Cline f95e368040 fix: eslint ENOTEMPTY (#2252) 2025-08-25 23:11:38 -05:00
Timo Clasen e18b2dc58e fix: model flag in non interactive mode (#2249) 2025-08-25 15:06:54 -05:00
Frank d06f6bafcb Add opencode workflow 2025-08-26 01:46:16 +08:00
Frank 0a9c369cff Add opencode workflow 2025-08-26 01:40:52 +08:00
opencode b051d05094 release: v0.5.27 2025-08-25 17:10:18 +00:00
adamdotdevin b88b0e0eb5 fix(tui): too early 2025-08-25 12:04:49 -05:00
opencode 79064a8446 release: v0.5.26 2025-08-25 16:54:15 +00:00
adamdotdevin 0002d2a473 fix(tui): wording 2025-08-25 16:38:25 +00:00
opencode 29630f4287 release: v0.5.25 2025-08-25 16:38:24 +00:00
adamdotdevin 1fcf31e299 fix(tui): sort custom commands lower 2025-08-25 11:32:15 -05:00
adamdotdevin e580176bbb fix(tui): sort custom commands lower 2025-08-25 11:29:56 -05:00
adamdotdevin d1afeb738e feat(tui): grok free 2025-08-25 11:27:58 -05:00
Jay V b958162dc5 docs: edit 2025-08-25 12:11:02 -04:00
adamdotdevin 343cfa9f63 fix(tui): fix logo color 2025-08-25 10:08:52 -05:00
adamdotdevin 726cf7631e chore: cleanup 2025-08-25 10:08:10 -05:00
GitHub Action 4313541071 ignore: update download stats 2025-08-25 2025-08-25 12:04:21 +00:00
Aiden Cline c58e3491a3 docs: fix shell examples (#2236) 2025-08-24 23:53:39 -05:00
opencode e14226d3d1 release: v0.5.24 2025-08-24 23:01:00 +00:00
Dax Raad 40b73f42c0 ci: tweak 2025-08-24 18:55:44 -04:00
opencode 5ad4cd97b1 release: v0.5.23 2025-08-24 22:53:37 +00:00
Dax Raad 4433a1452c ci: retry clone 2025-08-24 18:48:03 -04:00
Dax Raad 2168ba93da ci: ignore 2025-08-24 18:31:44 -04:00
Frank 76cc637cb5 Add opencode workflow 2025-08-25 06:16:21 +08:00
Frank 6043b7bd7e Add opencode workflow 2025-08-25 06:14:47 +08:00
Frank b10d087d12 Add opencode workflow 2025-08-25 03:39:11 +08:00
Frank 6eba62478c Add opencode workflow 2025-08-25 03:38:02 +08:00
Aiden Cline 8e27f9bef7 fix: command model selection (#2219) 2025-08-24 12:06:48 -05:00
GitHub Action d23eefe8bd ignore: update download stats 2025-08-24 2025-08-24 12:03:59 +00:00
Aiden Cline cdb4f5b57c docs: fix plan agent docs (#2215) 2025-08-23 14:52:02 -05:00
OpeOginni da8581f636 docs: document editor --wait flag (#2209)
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-08-23 14:43:20 -05:00
Aiden Cline 9f2b35351f docs: document out of box lsps (#2213) 2025-08-23 14:22:22 -05:00
opencode e322384c2d release: v0.5.18 2025-08-23 16:27:02 +00:00
Dax Raad 41f79a632e ci: stuff 2025-08-23 12:21:58 -04:00
Dax Raad 9d714c74ca ci: ignore 2025-08-23 12:10:08 -04:00
Johnny a3b293febb docs: fix nodejs installation commands (#2193) 2025-08-23 08:23:24 -05:00
GitHub Action 21e88bc2ad ignore: update download stats 2025-08-23 2025-08-23 12:03:48 +00:00
Vasiliy Kulikov cccd583769 feat(lsp): option to disable lsps installing automatically (#1997)
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-08-22 22:39:19 -05:00
Aiden Cline f4ccf0457f fix: count reasoning tokens (#2187) 2025-08-22 18:21:39 -05:00
Aiden Cline 95ec6d7a10 ignore: update json schema for better lsp dx (#2186) 2025-08-22 17:59:18 -05:00
Jay V 66a9670113 docs: edit 2025-08-22 18:36:17 -04:00
Jay V f3af7ff6ff docs: update 2025-08-22 18:34:35 -04:00
Dax Raad 99c26eb341 ignore: typecheck 2025-08-22 18:31:51 -04:00
Dax Raad af415f7a92 add sse streaming to sdk 2025-08-22 18:30:25 -04:00
Lubos 902beaa7ab chore(openapi): set correct content type for server-sent events (#2045) 2025-08-22 17:51:24 -04:00
Dax Raad 260d58f3b7 docs: add file names to code block titles in commands.mdx 2025-08-22 17:23:59 -04:00
Dax Raad db134b91cf docs: add commands page to sidebar 2025-08-22 17:23:59 -04:00
opencode 32f47c6618 release: v0.5.15 2025-08-22 21:16:23 +00:00
Aiden Cline 66e626dee0 fix: format error log (#2184) 2025-08-22 16:09:15 -05:00
Dax 1bd97ef802 slash commands (#2157)
Co-authored-by: adamdotdevin <2363879+adamdottv@users.noreply.github.com>
2025-08-22 17:04:28 -04:00
Jay V f2f66a2eff docs: edit 2025-08-22 15:14:02 -04:00
Jay V f5ff5243d3 docs: edit 2025-08-22 13:54:56 -04:00
Aiden Cline 43610a5671 docs: remove fake model (#2175) 2025-08-22 11:55:11 -05:00
Dax e8bdd3eb25 Update duplicate-issues.yml 2025-08-22 08:52:39 -04:00
GitHub Action 5627918b6f ignore: update download stats 2025-08-22 2025-08-22 12:04:13 +00:00
Thai Nguyen Hung d7232c83f2 fix: correct typo in LSP documentation (#2164) 2025-08-22 06:43:24 -05:00
Aiden Cline fa04ba35ad fix: error logging (#2165) 2025-08-21 23:27:49 -05:00
Dax Raad 7a29904deb deal with non existing cache folder 2025-08-21 22:58:39 -04:00
Aiden Cline e388c09f62 tweak: adjust plan agent to ask when running bash, give it edit tooli… (#2150) 2025-08-21 18:25:31 -04:00
Dax Raad f15660da75 ignore: docs agent 2025-08-21 17:15:43 -04:00
Dax Raad bfcadbb79f docs: update SDK documentation 2025-08-21 17:15:21 -04:00
Dax Raad 5210cbf1a5 add createOpencodeServer to js sdk and wait for readiness. always use random port for opencode serve. add /client and /server imports for js sdk 2025-08-21 17:13:24 -04:00
Aiden Cline 1cdf9573c5 fix: if lsp fails to spawn it shouldn't inject errors into edit diagnostics (#2145) 2025-08-21 12:06:32 -05:00
Dax Raad 993f9862f0 fix sdk config type 2025-08-21 13:00:16 -04:00
Dax Raad 269eb0519d allow importing sdk from @opencode-ai/sdk/server and @opencode-ai/sdk/client 2025-08-21 12:58:37 -04:00
zWing 8d87a4bfe1 chore: add export types in js-sdk (#1923)
Co-authored-by: zwingzheng <zwingzheng@tencent.com>
2025-08-21 11:06:27 -05:00
zWing 04548dd1a7 fix(js-sdk): fix types in session.chat (#1925)
Co-authored-by: zwingzheng <zwingzheng@tencent.com>
Co-authored-by: rekram1-node <aidenpcline@gmail.com>
2025-08-21 10:44:20 -05:00
Denys Pavlov 99bc8fe616 fix: preserve cache dir on cleanup (#2126) 2025-08-21 15:27:25 +00:00
Dax Raad 75523d978c await config hooks 2025-08-21 15:27:25 +00:00
opencode 9dea751f6d release: v0.5.13 2025-08-21 15:27:25 +00:00
Dax Raad b8322e5b19 add plugin hook for config 2025-08-21 11:22:24 -04:00
GitHub Action 8dd6ab0d2f ignore: update download stats 2025-08-21 2025-08-21 12:04:21 +00:00
Aiden Cline 08397fcdc8 tweak: adjust plan -> build transition prompt (#2111) 2025-08-21 06:52:38 -05:00
Frank 00ccaabb12 fix do migration 2025-08-21 18:02:32 +08:00
Frank 17468305cd fix do migration 2025-08-21 17:52:55 +08:00
Jay V c53086ea04 docs: update 2025-08-20 17:58:56 -04:00
Jay V b707f3053a docs: gitlab 2025-08-20 17:51:16 -04:00
Jay V a4729084cf docs: edit 2025-08-20 17:39:37 -04:00
Lee Tickett 270820e21a docs: Add GitLab CLI agent integration doc (#2103) 2025-08-20 17:37:43 -04:00
Dax Raad 68bed18e84 ignore: cloud stuff 2025-08-20 17:01:18 -04:00
Vincent Bernat 26b025bb4c fix: ignore case when checking Qwen in model ID for todos (#2122) 2025-08-20 14:44:27 -05:00
Jay V 130979862b docs: edit 2025-08-20 18:22:48 +00:00
opencode b1d40e699b release: v0.5.12 2025-08-20 18:22:48 +00:00
Jay V 9bb4424eb9 docs: edit server 2025-08-20 14:13:02 -04:00
Dax Raad 3b6566731f ci: turn back on aur 2025-08-20 12:46:17 -04:00
opencode e402e6801f release: v0.5.11 2025-08-20 16:36:05 +00:00
Dax Raad f040dc3ec7 ignore: remove import 2025-08-20 12:29:24 -04:00
Dax Raad cec1fa8bb2 remove auto browser open for now 2025-08-20 12:28:00 -04:00
1837 changed files with 80219 additions and 19305 deletions
+20
View File
@@ -0,0 +1,20 @@
name: "Setup Bun"
description: "Setup Bun with caching and install dependencies"
runs:
using: "composite"
steps:
- name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Cache ~/.bun
id: cache-bun
uses: actions/cache@v4
with:
path: ~/.bun
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lockb', 'bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install
shell: bash
+3 -5
View File
@@ -15,13 +15,11 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: oven-sh/setup-bun@v1
with:
bun-version: 1.2.19
- run: bun install
- uses: ./.github/actions/setup-bun
- run: bun sst deploy --stage=${{ github.ref_name }}
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
PLANETSCALE_SERVICE_TOKEN_NAME: ${{ secrets.PLANETSCALE_SERVICE_TOKEN_NAME }}
PLANETSCALE_SERVICE_TOKEN: ${{ secrets.PLANETSCALE_SERVICE_TOKEN }}
STRIPE_SECRET_KEY: ${{ github.ref_name == 'production' && secrets.STRIPE_SECRET_KEY_PROD || secrets.STRIPE_SECRET_KEY_DEV }}
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
"webfetch": "deny"
}
run: |
opencode run -m anthropic/claude-sonnet-4-20250514 "A new issue has been created: '${{ github.event.issue.title }}'
opencode run -m anthropic/claude-sonnet-4-20250514 "A new issue has been created:'
Issue number:
${{ github.event.issue.number }}
+29
View File
@@ -0,0 +1,29 @@
name: format
on:
push:
branches-ignore:
- production
pull_request:
branches-ignore:
- production
workflow_dispatch:
jobs:
format:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: run
run: |
./script/format.ts
env:
CI: true
+1 -1
View File
@@ -2,7 +2,7 @@ name: discord
on:
release:
types: [published] # fires only when a release is published
types: [published] # fires only when a release is published
jobs:
notify:
+5 -5
View File
@@ -13,17 +13,17 @@ jobs:
startsWith(github.event.comment.body, '/opencode')
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
contents: read
pull-requests: read
issues: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Run opencode
uses: sst/opencode/github@latest
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
with:
model: anthropic/claude-sonnet-4-20250514
model: opencode/kimi-k2
+1 -4
View File
@@ -19,16 +19,13 @@ jobs:
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.2.19
- uses: ./.github/actions/setup-bun
- run: git fetch --force --tags
- run: bun install -g @vscode/vsce
- name: Publish
run: |
bun install
./script/publish
working-directory: ./sdks/vscode
env:
+16 -23
View File
@@ -1,17 +1,17 @@
name: publish
run-name: "${{ format('v{0}', inputs.version) }}"
run-name: "${{ format('release {0}', inputs.bump) }}"
on:
workflow_dispatch:
inputs:
version:
description: "Version to publish"
bump:
description: "Bump major, minor, or patch"
required: true
type: string
title:
description: "Custom title for this run"
required: false
type: string
type: choice
options:
- major
- minor
- patch
concurrency: ${{ github.workflow }}-${{ github.ref }}
@@ -35,18 +35,7 @@ jobs:
cache: true
cache-dependency-path: go.sum
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.2.19
- name: Cache ~/.bun
id: cache-bun
uses: actions/cache@v3
with:
path: ~/.bun
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- uses: ./.github/actions/setup-bun
- name: Install makepkg
run: |
@@ -60,13 +49,17 @@ jobs:
git config --global user.email "opencode@sst.dev"
git config --global user.name "opencode"
ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts || true
- name: Install dependencies
run: bun install
- name: Install OpenCode
run: curl -fsSL https://opencode.ai/install | bash
- name: Publish
run: |
OPENCODE_VERSION=${{ inputs.version }} ./script/publish.ts
./script/publish.ts
env:
OPENCODE_BUMP: ${{ inputs.bump }}
OPENCODE_CHANNEL: latest
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
AUR_KEY: ${{ secrets.AUR_KEY }}
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
+34
View File
@@ -0,0 +1,34 @@
name: snapshot
on:
push:
branches:
- dev
- opentui
concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- run: git fetch --force --tags
- uses: actions/setup-go@v5
with:
go-version: ">=1.24.0"
cache: true
cache-dependency-path: go.sum
- uses: ./.github/actions/setup-bun
- name: Publish
run: |
./script/publish.ts
env:
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
+1 -3
View File
@@ -16,9 +16,7 @@ jobs:
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
uses: ./.github/actions/setup-bun
- name: Run stats script
run: bun script/stats.ts
+30
View File
@@ -0,0 +1,30 @@
name: test
on:
push:
branches-ignore:
- production
pull_request:
branches-ignore:
- production
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: run
run: |
git config --global user.email "bot@opencode.ai"
git config --global user.name "opencode"
bun turbo typecheck
bun turbo test
env:
CI: true
+2 -7
View File
@@ -1,4 +1,4 @@
name: Typecheck
name: typecheck
on:
pull_request:
@@ -13,12 +13,7 @@ jobs:
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: 1.2.19
- name: Install dependencies
run: bun install
uses: ./.github/actions/setup-bun
- name: Run typecheck
run: bun typecheck
+3
View File
@@ -1,5 +1,6 @@
.DS_Store
node_modules
.worktrees
.sst
.env
.idea
@@ -7,3 +8,5 @@ node_modules
openapi.json
playground
tmp
dist
.turbo
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
bun run typecheck
+3 -1
View File
@@ -13,7 +13,7 @@ avoid repeating the title of the page, should be 5-10 words long
Chunks of text should not be more than 2 sentences long
Each section is spearated by a divider of 3 dashes
Each section is separated by a divider of 3 dashes
The section titles are short with only the first letter of the word capitalized
@@ -27,3 +27,5 @@ Check out the /packages/web/src/content/docs/docs/index.mdx as an example.
For JS or TS code snippets remove trailing semicolons and any trailing commas
that might not be needed.
If you are making a commit prefix the commit message with `docs:`
+20
View File
@@ -0,0 +1,20 @@
---
description: Git commit and push
---
commit and push
make sure it includes a prefix like
docs:
tui:
core:
ci:
ignore:
wip:
For anything in the packages/web use the docs: prefix.
For anything in the packages/app use the ignore: prefix.
prefer to explain WHY something was done from an end user perspective instead of
WHAT was done.
+8
View File
@@ -0,0 +1,8 @@
---
description: hello world
---
hey there $ARGUMENTS
!`ls`
check out @README.md
+5
View File
@@ -0,0 +1,5 @@
---
description: Spellcheck all markdown file changes
---
Look at all the unstaged changes to markdown (.md, .mdx) files, pull out the lines that have changed, and check for spelling and grammar errors.
+35
View File
@@ -10,3 +10,38 @@
- AVOID `let` statements
- PREFER single word variable names where possible
- Use as many bun apis as possible like Bun.file()
## Debugging
- To test opencode in the `packages/opencode` directory you can run `bun dev`
## Tool Calling
- ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE. Here is an example illustrating how to execute 3 parallel file reads in this chat environnement:
json
{
"recipient_name": "multi_tool_use.parallel",
"parameters": {
"tool_uses": [
{
"recipient_name": "functions.read",
"parameters": {
"filePath": "path/to/file.tsx"
}
},
{
"recipient_name": "functions.read",
"parameters": {
"filePath": "path/to/file.ts"
}
},
{
"recipient_name": "functions.read",
"parameters": {
"filePath": "path/to/file.md"
}
}
]
}
}
+15 -14
View File
@@ -1,20 +1,20 @@
<p align="center">
<a href="https://opencode.ai">
<picture>
<source srcset="packages/web/src/assets/logo-ornate-dark.svg" media="(prefers-color-scheme: dark)">
<source srcset="packages/web/src/assets/logo-ornate-light.svg" media="(prefers-color-scheme: light)">
<img src="packages/web/src/assets/logo-ornate-light.svg" alt="opencode logo">
<source srcset="packages/console/app/src/asset/logo-ornate-dark.svg" media="(prefers-color-scheme: dark)">
<source srcset="packages/console/app/src/asset/logo-ornate-light.svg" media="(prefers-color-scheme: light)">
<img src="packages/console/app/src/asset/logo-ornate-light.svg" alt="OpenCode logo">
</picture>
</a>
</p>
<p align="center">AI coding agent, built for the terminal.</p>
<p align="center">The AI coding agent built for the terminal.</p>
<p align="center">
<a href="https://opencode.ai/discord"><img alt="Discord" src="https://img.shields.io/discord/1391832426048651334?style=flat-square&label=discord" /></a>
<a href="https://www.npmjs.com/package/opencode-ai"><img alt="npm" src="https://img.shields.io/npm/v/opencode-ai?style=flat-square" /></a>
<a href="https://github.com/sst/opencode/actions/workflows/publish.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/sst/opencode/publish.yml?style=flat-square&branch=dev" /></a>
</p>
[![opencode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai)
[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai)
---
@@ -50,11 +50,11 @@ XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash
### Documentation
For more info on how to configure opencode [**head over to our docs**](https://opencode.ai/docs).
For more info on how to configure OpenCode [**head over to our docs**](https://opencode.ai/docs).
### Contributing
opencode is an opinionated tool so any fundamental feature needs to go through a
OpenCode is an opinionated tool so any fundamental feature needs to go through a
design process with the core team.
> [!IMPORTANT]
@@ -74,9 +74,9 @@ Take a look at the git history to see what kind of PRs we end up merging.
> [!NOTE]
> If you do not follow the above guidelines we might close your PR.
To run opencode locally you need.
To run OpenCode locally you need.
- Bun
- Bun 1.3 or higher
- Golang 1.24.x
And run.
@@ -88,7 +88,7 @@ $ bun dev
#### Development Notes
**API Client**: After making changes to the TypeScript API endpoints in `packages/opencode/src/server/server.ts`, you will need the opencode team to generate a new stainless sdk for the clients.
**API Client**: After making changes to the TypeScript API endpoints in `packages/opencode/src/server/server.ts`, you will need the OpenCode team to generate a new stainless sdk for the clients.
### FAQ
@@ -97,9 +97,10 @@ $ bun dev
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 Anthropic is recommended, opencode can be used with 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.
- 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 can drive it remotely from a mobile app. Meaning that the TUI frontend is just one of the possible clients.
- Not coupled to any provider. Although Anthropic is recommended, OpenCode can be used with 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.
- Out of the box 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 can drive it remotely from a mobile app. Meaning that the TUI frontend is just one of the possible clients.
#### What's the other repo?
@@ -107,4 +108,4 @@ The other confusingly named repo has no relation to this one. You can [read the
---
**Join our community** [Discord](https://discord.gg/opencode) | [YouTube](https://www.youtube.com/c/sst-dev) | [X.com](https://x.com/SST_dev)
**Join our community** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode)
+110 -54
View File
@@ -1,56 +1,112 @@
# Download Stats
| Date | GitHub Downloads | npm Downloads | Total |
| ---------- | ---------------- | ---------------- | ----------------- |
| 2025-06-29 | 18,789 (+0) | 39,420 (+0) | 58,209 (+0) |
| 2025-06-30 | 20,127 (+1,338) | 41,059 (+1,639) | 61,186 (+2,977) |
| 2025-07-01 | 22,108 (+1,981) | 43,745 (+2,686) | 65,853 (+4,667) |
| 2025-07-02 | 24,814 (+2,706) | 46,168 (+2,423) | 70,982 (+5,129) |
| 2025-07-03 | 27,834 (+3,020) | 49,955 (+3,787) | 77,789 (+6,807) |
| 2025-07-04 | 30,608 (+2,774) | 54,758 (+4,803) | 85,366 (+7,577) |
| 2025-07-05 | 32,524 (+1,916) | 58,371 (+3,613) | 90,895 (+5,529) |
| 2025-07-06 | 33,766 (+1,242) | 59,694 (+1,323) | 93,460 (+2,565) |
| 2025-07-08 | 38,052 (+4,286) | 64,468 (+4,774) | 102,520 (+9,060) |
| 2025-07-09 | 40,924 (+2,872) | 67,935 (+3,467) | 108,859 (+6,339) |
| 2025-07-10 | 43,796 (+2,872) | 71,402 (+3,467) | 115,198 (+6,339) |
| 2025-07-11 | 46,982 (+3,186) | 77,462 (+6,060) | 124,444 (+9,246) |
| 2025-07-12 | 49,302 (+2,320) | 82,177 (+4,715) | 131,479 (+7,035) |
| 2025-07-13 | 50,803 (+1,501) | 86,394 (+4,217) | 137,197 (+5,718) |
| 2025-07-14 | 53,283 (+2,480) | 87,860 (+1,466) | 141,143 (+3,946) |
| 2025-07-15 | 57,590 (+4,307) | 91,036 (+3,176) | 148,626 (+7,483) |
| 2025-07-16 | 62,313 (+4,723) | 95,258 (+4,222) | 157,571 (+8,945) |
| 2025-07-17 | 66,684 (+4,371) | 100,048 (+4,790) | 166,732 (+9,161) |
| 2025-07-18 | 70,379 (+3,695) | 102,587 (+2,539) | 172,966 (+6,234) |
| 2025-07-19 | 73,497 (+3,117) | 105,904 (+3,317) | 179,401 (+6,434) |
| 2025-07-20 | 76,453 (+2,956) | 109,044 (+3,140) | 185,497 (+6,096) |
| 2025-07-21 | 80,197 (+3,744) | 113,537 (+4,493) | 193,734 (+8,237) |
| 2025-07-22 | 84,251 (+4,054) | 118,073 (+4,536) | 202,324 (+8,590) |
| 2025-07-23 | 88,589 (+4,338) | 121,436 (+3,363) | 210,025 (+7,701) |
| 2025-07-24 | 92,469 (+3,880) | 124,091 (+2,655) | 216,560 (+6,535) |
| 2025-07-25 | 96,417 (+3,948) | 126,985 (+2,894) | 223,402 (+6,842) |
| 2025-07-26 | 100,646 (+4,229) | 131,411 (+4,426) | 232,057 (+8,655) |
| 2025-07-27 | 102,644 (+1,998) | 134,736 (+3,325) | 237,380 (+5,323) |
| 2025-07-28 | 105,446 (+2,802) | 136,016 (+1,280) | 241,462 (+4,082) |
| 2025-07-29 | 108,998 (+3,552) | 137,542 (+1,526) | 246,540 (+5,078) |
| 2025-07-30 | 113,544 (+4,546) | 140,317 (+2,775) | 253,861 (+7,321) |
| 2025-07-31 | 118,339 (+4,795) | 143,344 (+3,027) | 261,683 (+7,822) |
| 2025-08-01 | 123,539 (+5,200) | 146,680 (+3,336) | 270,219 (+8,536) |
| 2025-08-02 | 127,864 (+4,325) | 149,236 (+2,556) | 277,100 (+6,881) |
| 2025-08-03 | 131,397 (+3,533) | 150,451 (+1,215) | 281,848 (+4,748) |
| 2025-08-04 | 136,266 (+4,869) | 153,260 (+2,809) | 289,526 (+7,678) |
| 2025-08-05 | 141,596 (+5,330) | 155,752 (+2,492) | 297,348 (+7,822) |
| 2025-08-06 | 147,067 (+5,471) | 158,309 (+2,557) | 305,376 (+8,028) |
| 2025-08-07 | 152,591 (+5,524) | 160,889 (+2,580) | 313,480 (+8,104) |
| 2025-08-08 | 158,187 (+5,596) | 163,448 (+2,559) | 321,635 (+8,155) |
| 2025-08-09 | 162,770 (+4,583) | 165,721 (+2,273) | 328,491 (+6,856) |
| 2025-08-10 | 165,695 (+2,925) | 167,109 (+1,388) | 332,804 (+4,313) |
| 2025-08-11 | 169,297 (+3,602) | 167,953 (+844) | 337,250 (+4,446) |
| 2025-08-12 | 176,307 (+7,010) | 171,876 (+3,923) | 348,183 (+10,933) |
| 2025-08-13 | 182,997 (+6,690) | 177,182 (+5,306) | 360,179 (+11,996) |
| 2025-08-14 | 189,063 (+6,066) | 179,741 (+2,559) | 368,804 (+8,625) |
| 2025-08-15 | 193,608 (+4,545) | 181,792 (+2,051) | 375,400 (+6,596) |
| 2025-08-16 | 198,118 (+4,510) | 184,558 (+2,766) | 382,676 (+7,276) |
| 2025-08-17 | 201,299 (+3,181) | 186,269 (+1,711) | 387,568 (+4,892) |
| 2025-08-18 | 204,559 (+3,260) | 187,399 (+1,130) | 391,958 (+4,390) |
| 2025-08-19 | 209,814 (+5,255) | 189,668 (+2,269) | 399,482 (+7,524) |
| 2025-08-20 | 214,497 (+4,683) | 191,481 (+1,813) | 405,978 (+6,496) |
| Date | GitHub Downloads | npm Downloads | Total |
| ---------- | ----------------- | ----------------- | ----------------- |
| 2025-06-29 | 18,789 (+0) | 39,420 (+0) | 58,209 (+0) |
| 2025-06-30 | 20,127 (+1,338) | 41,059 (+1,639) | 61,186 (+2,977) |
| 2025-07-01 | 22,108 (+1,981) | 43,745 (+2,686) | 65,853 (+4,667) |
| 2025-07-02 | 24,814 (+2,706) | 46,168 (+2,423) | 70,982 (+5,129) |
| 2025-07-03 | 27,834 (+3,020) | 49,955 (+3,787) | 77,789 (+6,807) |
| 2025-07-04 | 30,608 (+2,774) | 54,758 (+4,803) | 85,366 (+7,577) |
| 2025-07-05 | 32,524 (+1,916) | 58,371 (+3,613) | 90,895 (+5,529) |
| 2025-07-06 | 33,766 (+1,242) | 59,694 (+1,323) | 93,460 (+2,565) |
| 2025-07-08 | 38,052 (+4,286) | 64,468 (+4,774) | 102,520 (+9,060) |
| 2025-07-09 | 40,924 (+2,872) | 67,935 (+3,467) | 108,859 (+6,339) |
| 2025-07-10 | 43,796 (+2,872) | 71,402 (+3,467) | 115,198 (+6,339) |
| 2025-07-11 | 46,982 (+3,186) | 77,462 (+6,060) | 124,444 (+9,246) |
| 2025-07-12 | 49,302 (+2,320) | 82,177 (+4,715) | 131,479 (+7,035) |
| 2025-07-13 | 50,803 (+1,501) | 86,394 (+4,217) | 137,197 (+5,718) |
| 2025-07-14 | 53,283 (+2,480) | 87,860 (+1,466) | 141,143 (+3,946) |
| 2025-07-15 | 57,590 (+4,307) | 91,036 (+3,176) | 148,626 (+7,483) |
| 2025-07-16 | 62,313 (+4,723) | 95,258 (+4,222) | 157,571 (+8,945) |
| 2025-07-17 | 66,684 (+4,371) | 100,048 (+4,790) | 166,732 (+9,161) |
| 2025-07-18 | 70,379 (+3,695) | 102,587 (+2,539) | 172,966 (+6,234) |
| 2025-07-19 | 73,497 (+3,117) | 105,904 (+3,317) | 179,401 (+6,434) |
| 2025-07-20 | 76,453 (+2,956) | 109,044 (+3,140) | 185,497 (+6,096) |
| 2025-07-21 | 80,197 (+3,744) | 113,537 (+4,493) | 193,734 (+8,237) |
| 2025-07-22 | 84,251 (+4,054) | 118,073 (+4,536) | 202,324 (+8,590) |
| 2025-07-23 | 88,589 (+4,338) | 121,436 (+3,363) | 210,025 (+7,701) |
| 2025-07-24 | 92,469 (+3,880) | 124,091 (+2,655) | 216,560 (+6,535) |
| 2025-07-25 | 96,417 (+3,948) | 126,985 (+2,894) | 223,402 (+6,842) |
| 2025-07-26 | 100,646 (+4,229) | 131,411 (+4,426) | 232,057 (+8,655) |
| 2025-07-27 | 102,644 (+1,998) | 134,736 (+3,325) | 237,380 (+5,323) |
| 2025-07-28 | 105,446 (+2,802) | 136,016 (+1,280) | 241,462 (+4,082) |
| 2025-07-29 | 108,998 (+3,552) | 137,542 (+1,526) | 246,540 (+5,078) |
| 2025-07-30 | 113,544 (+4,546) | 140,317 (+2,775) | 253,861 (+7,321) |
| 2025-07-31 | 118,339 (+4,795) | 143,344 (+3,027) | 261,683 (+7,822) |
| 2025-08-01 | 123,539 (+5,200) | 146,680 (+3,336) | 270,219 (+8,536) |
| 2025-08-02 | 127,864 (+4,325) | 149,236 (+2,556) | 277,100 (+6,881) |
| 2025-08-03 | 131,397 (+3,533) | 150,451 (+1,215) | 281,848 (+4,748) |
| 2025-08-04 | 136,266 (+4,869) | 153,260 (+2,809) | 289,526 (+7,678) |
| 2025-08-05 | 141,596 (+5,330) | 155,752 (+2,492) | 297,348 (+7,822) |
| 2025-08-06 | 147,067 (+5,471) | 158,309 (+2,557) | 305,376 (+8,028) |
| 2025-08-07 | 152,591 (+5,524) | 160,889 (+2,580) | 313,480 (+8,104) |
| 2025-08-08 | 158,187 (+5,596) | 163,448 (+2,559) | 321,635 (+8,155) |
| 2025-08-09 | 162,770 (+4,583) | 165,721 (+2,273) | 328,491 (+6,856) |
| 2025-08-10 | 165,695 (+2,925) | 167,109 (+1,388) | 332,804 (+4,313) |
| 2025-08-11 | 169,297 (+3,602) | 167,953 (+844) | 337,250 (+4,446) |
| 2025-08-12 | 176,307 (+7,010) | 171,876 (+3,923) | 348,183 (+10,933) |
| 2025-08-13 | 182,997 (+6,690) | 177,182 (+5,306) | 360,179 (+11,996) |
| 2025-08-14 | 189,063 (+6,066) | 179,741 (+2,559) | 368,804 (+8,625) |
| 2025-08-15 | 193,608 (+4,545) | 181,792 (+2,051) | 375,400 (+6,596) |
| 2025-08-16 | 198,118 (+4,510) | 184,558 (+2,766) | 382,676 (+7,276) |
| 2025-08-17 | 201,299 (+3,181) | 186,269 (+1,711) | 387,568 (+4,892) |
| 2025-08-18 | 204,559 (+3,260) | 187,399 (+1,130) | 391,958 (+4,390) |
| 2025-08-19 | 209,814 (+5,255) | 189,668 (+2,269) | 399,482 (+7,524) |
| 2025-08-20 | 214,497 (+4,683) | 191,481 (+1,813) | 405,978 (+6,496) |
| 2025-08-21 | 220,465 (+5,968) | 194,784 (+3,303) | 415,249 (+9,271) |
| 2025-08-22 | 225,899 (+5,434) | 197,204 (+2,420) | 423,103 (+7,854) |
| 2025-08-23 | 229,005 (+3,106) | 199,238 (+2,034) | 428,243 (+5,140) |
| 2025-08-24 | 232,098 (+3,093) | 201,157 (+1,919) | 433,255 (+5,012) |
| 2025-08-25 | 236,607 (+4,509) | 202,650 (+1,493) | 439,257 (+6,002) |
| 2025-08-26 | 242,783 (+6,176) | 205,242 (+2,592) | 448,025 (+8,768) |
| 2025-08-27 | 248,409 (+5,626) | 205,242 (+0) | 453,651 (+5,626) |
| 2025-08-28 | 252,796 (+4,387) | 205,242 (+0) | 458,038 (+4,387) |
| 2025-08-29 | 256,045 (+3,249) | 211,075 (+5,833) | 467,120 (+9,082) |
| 2025-08-30 | 258,863 (+2,818) | 212,397 (+1,322) | 471,260 (+4,140) |
| 2025-08-31 | 262,004 (+3,141) | 213,944 (+1,547) | 475,948 (+4,688) |
| 2025-09-01 | 265,359 (+3,355) | 215,115 (+1,171) | 480,474 (+4,526) |
| 2025-09-02 | 270,483 (+5,124) | 217,075 (+1,960) | 487,558 (+7,084) |
| 2025-09-03 | 274,793 (+4,310) | 219,755 (+2,680) | 494,548 (+6,990) |
| 2025-09-04 | 280,430 (+5,637) | 222,103 (+2,348) | 502,533 (+7,985) |
| 2025-09-05 | 283,769 (+3,339) | 223,793 (+1,690) | 507,562 (+5,029) |
| 2025-09-06 | 286,245 (+2,476) | 225,036 (+1,243) | 511,281 (+3,719) |
| 2025-09-07 | 288,623 (+2,378) | 225,866 (+830) | 514,489 (+3,208) |
| 2025-09-08 | 293,341 (+4,718) | 227,073 (+1,207) | 520,414 (+5,925) |
| 2025-09-09 | 300,036 (+6,695) | 229,788 (+2,715) | 529,824 (+9,410) |
| 2025-09-10 | 307,287 (+7,251) | 233,435 (+3,647) | 540,722 (+10,898) |
| 2025-09-11 | 314,083 (+6,796) | 237,356 (+3,921) | 551,439 (+10,717) |
| 2025-09-12 | 321,046 (+6,963) | 240,728 (+3,372) | 561,774 (+10,335) |
| 2025-09-13 | 324,894 (+3,848) | 245,539 (+4,811) | 570,433 (+8,659) |
| 2025-09-14 | 328,876 (+3,982) | 248,245 (+2,706) | 577,121 (+6,688) |
| 2025-09-15 | 334,201 (+5,325) | 250,983 (+2,738) | 585,184 (+8,063) |
| 2025-09-16 | 342,609 (+8,408) | 255,264 (+4,281) | 597,873 (+12,689) |
| 2025-09-17 | 351,117 (+8,508) | 260,970 (+5,706) | 612,087 (+14,214) |
| 2025-09-18 | 358,717 (+7,600) | 266,922 (+5,952) | 625,639 (+13,552) |
| 2025-09-19 | 365,401 (+6,684) | 271,859 (+4,937) | 637,260 (+11,621) |
| 2025-09-20 | 372,092 (+6,691) | 276,917 (+5,058) | 649,009 (+11,749) |
| 2025-09-21 | 377,079 (+4,987) | 280,261 (+3,344) | 657,340 (+8,331) |
| 2025-09-22 | 382,492 (+5,413) | 284,009 (+3,748) | 666,501 (+9,161) |
| 2025-09-23 | 387,008 (+4,516) | 289,129 (+5,120) | 676,137 (+9,636) |
| 2025-09-24 | 393,325 (+6,317) | 294,927 (+5,798) | 688,252 (+12,115) |
| 2025-09-25 | 398,879 (+5,554) | 301,663 (+6,736) | 700,542 (+12,290) |
| 2025-09-26 | 404,334 (+5,455) | 306,713 (+5,050) | 711,047 (+10,505) |
| 2025-09-27 | 411,618 (+7,284) | 317,763 (+11,050) | 729,381 (+18,334) |
| 2025-09-28 | 414,910 (+3,292) | 322,522 (+4,759) | 737,432 (+8,051) |
| 2025-09-29 | 419,919 (+5,009) | 328,033 (+5,511) | 747,952 (+10,520) |
| 2025-09-30 | 427,991 (+8,072) | 336,472 (+8,439) | 764,463 (+16,511) |
| 2025-10-01 | 433,591 (+5,600) | 341,742 (+5,270) | 775,333 (+10,870) |
| 2025-10-02 | 440,852 (+7,261) | 348,099 (+6,357) | 788,951 (+13,618) |
| 2025-10-03 | 446,829 (+5,977) | 359,937 (+11,838) | 806,766 (+17,815) |
| 2025-10-04 | 452,561 (+5,732) | 370,386 (+10,449) | 822,947 (+16,181) |
| 2025-10-05 | 455,559 (+2,998) | 374,745 (+4,359) | 830,304 (+7,357) |
| 2025-10-06 | 460,927 (+5,368) | 379,489 (+4,744) | 840,416 (+10,112) |
| 2025-10-07 | 467,336 (+6,409) | 385,438 (+5,949) | 852,774 (+12,358) |
| 2025-10-08 | 474,643 (+7,307) | 394,139 (+8,701) | 868,782 (+16,008) |
| 2025-10-09 | 479,203 (+4,560) | 400,526 (+6,387) | 879,729 (+10,947) |
| 2025-10-10 | 484,374 (+5,171) | 406,015 (+5,489) | 890,389 (+10,660) |
| 2025-10-11 | 488,427 (+4,053) | 414,699 (+8,684) | 903,126 (+12,737) |
| 2025-10-12 | 492,125 (+3,698) | 418,745 (+4,046) | 910,870 (+7,744) |
| 2025-10-14 | 505,130 (+13,005) | 429,286 (+10,541) | 934,416 (+23,546) |
| 2025-10-15 | 512,717 (+7,587) | 439,290 (+10,004) | 952,007 (+17,591) |
| 2025-10-16 | 517,719 (+5,002) | 447,137 (+7,847) | 964,856 (+12,849) |
+1652 -1236
View File
File diff suppressed because it is too large Load Diff
-9
View File
@@ -1,9 +0,0 @@
import { defineConfig } from "@solidjs/start/config"
export default defineConfig({
vite: {
server: {
allowedHosts: true,
},
},
})
-22
View File
@@ -1,22 +0,0 @@
{
"name": "@opencode/cloud-app",
"type": "module",
"scripts": {
"dev": "vinxi dev --host 0.0.0.0",
"build": "vinxi build",
"start": "vinxi start",
"version": "0.5.10"
},
"dependencies": {
"@ibm/plex": "6.4.1",
"@openauthjs/openauth": "0.0.0-20250322224806",
"@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.15.0",
"@solidjs/start": "^1.1.0",
"solid-js": "^1.9.5",
"vinxi": "^0.5.7"
},
"engines": {
"node": ">=22"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 664 B

-21
View File
@@ -1,21 +0,0 @@
import { MetaProvider, Title } from "@solidjs/meta";
import { Router } from "@solidjs/router";
import { FileRoutes } from "@solidjs/start/router";
import { Suspense } from "solid-js";
import "@ibm/plex/css/ibm-plex.css";
import "./app.css";
export default function App() {
return (
<Router
root={props => (
<MetaProvider>
<Title>SolidStart - Basic</Title>
<Suspense>{props.children}</Suspense>
</MetaProvider>
)}
>
<FileRoutes />
</Router>
);
}
-19
View File
@@ -1,19 +0,0 @@
<svg width="289" height="50" viewBox="0 0 289 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.5 16.5H24.5V33H8.5V16.5Z" fill="white" fill-opacity="0.2"/>
<path d="M48.5 16.5H64.5V33H48.5V16.5Z" fill="white" fill-opacity="0.2"/>
<path d="M120.5 16.5H136.5V33H120.5V16.5Z" fill="white" fill-opacity="0.2"/>
<path d="M160.5 16.5H176.5V33H160.5V16.5Z" fill="white" fill-opacity="0.2"/>
<path d="M192.5 16.5H208.5V33H192.5V16.5Z" fill="white" fill-opacity="0.2"/>
<path d="M232.5 16.5H248.5V33H232.5V16.5Z" fill="white" fill-opacity="0.2"/>
<path d="M264.5 0H288.5V8.5H272.5V16.5H288.5V25H272.5V33H288.5V41.5H264.5V0Z" fill="white" fill-opacity="0.95"/>
<path d="M248.5 0H224.5V41.5H248.5V33H232.5V8.5H248.5V0Z" fill="white" fill-opacity="0.95"/>
<path d="M256.5 8.5H248.5V33H256.5V8.5Z" fill="white" fill-opacity="0.95"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M184.5 0H216.5V41.5H184.5V0ZM208.5 8.5H192.5V33H208.5V8.5Z" fill="white" fill-opacity="0.95"/>
<path d="M144.5 8.5H136.5V41.5H144.5V8.5Z" fill="white" fill-opacity="0.5"/>
<path d="M136.5 0H112.5V41.5H120.5V8.5H136.5V0Z" fill="white" fill-opacity="0.5"/>
<path d="M80.5 0H104.5V8.5H88.5V16.5H104.5V25H88.5V33H104.5V41.5H80.5V0Z" fill="white" fill-opacity="0.5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M40.5 0H72.5V41.5H48.5V49.5H40.5V0ZM64.5 8.5H48.5V33H64.5V8.5Z" fill="white" fill-opacity="0.5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.5 0H32.5V41.5955H0.5V0ZM24.5 8.5H8.5V33H24.5V8.5Z" fill="white" fill-opacity="0.5"/>
<path d="M152.5 0H176.5V8.5H160.5V33H176.5V41.5H152.5V0Z" fill="white" fill-opacity="0.95"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 902 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 998 KiB

-24
View File
@@ -1,24 +0,0 @@
import { JSX } from "solid-js"
export function IconCopy(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
return (
<svg
{...props}
viewBox="0 0 512 512" >
<rect width="336" height="336" x="128" y="128" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32" rx="57" ry="57"></rect>
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="m383.5 128l.5-24a56.16 56.16 0 0 0-56-56H112a64.19 64.19 0 0 0-64 64v216a56.16 56.16 0 0 0 56 56h24"></path>
</svg>
)
}
export function IconCheck(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
return (
<svg
{...props}
viewBox="0 0 24 24" >
<path fill="currentColor" d="M9 16.17L5.53 12.7a.996.996 0 1 0-1.41 1.41l4.18 4.18c.39.39 1.02.39 1.41 0L20.29 7.71a.996.996 0 1 0-1.41-1.41z"></path>
</svg>
)
}
-28
View File
@@ -1,28 +0,0 @@
import { useSession } from "vinxi/http"
import { createClient } from "@openauthjs/openauth/client"
export const AuthClient = createClient({
clientID: "app",
issuer: "https://auth.dev.opencode.ai",
})
export interface AuthSession {
account: Record<string, {
id: string
email: string
}>
current?: string
}
export function useAuthSession() {
"use server"
return useSession<AuthSession>({
password: "0".repeat(32),
name: "auth"
})
}
export function AuthProvider() {
}
-4
View File
@@ -1,4 +0,0 @@
// @refresh reload
import { mount, StartClient } from "@solidjs/start/client";
mount(() => <StartClient />, document.getElementById("app")!);
-21
View File
@@ -1,21 +0,0 @@
// @refresh reload
import { createHandler, StartServer } from "@solidjs/start/server";
export default createHandler(() => (
<StartServer
document={({ assets, children, scripts }) => (
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
{assets}
</head>
<body data-color-mode="dark">
<div id="app">{children}</div>
{scripts}
</body>
</html>
)}
/>
));
-19
View File
@@ -1,19 +0,0 @@
import { Title } from "@solidjs/meta";
import { HttpStatusCode } from "@solidjs/start";
export default function NotFound() {
return (
<main>
<Title>Not Found</Title>
<HttpStatusCode code={404} />
<h1>Page Not Found</h1>
<p>
Visit{" "}
<a href="https://start.solidjs.com" target="_blank">
start.solidjs.com
</a>{" "}
to learn how to build SolidStart apps.
</p>
</main>
);
}
-257
View File
@@ -1,257 +0,0 @@
[data-page="home"] {
--color-bg: oklch(0.2097 0.008 274.53);
--color-border: oklch(0.46 0.02 269.88);
--color-text: #ffffff;
--color-text-secondary: oklch(0.72 0.01 270.15);
--color-text-dimmed: hsl(224, 7%, 46%);
padding: var(--space-6);
font-family: var(--font-mono);
color: var(--color-text);
a {
color: var(--color-text);
text-decoration: underline;
text-underline-offset: var(--space-0-75);
}
background: var(--color-bg);
position: fixed;
overflow-y: scroll;
inset: 0;
[data-component="content"] {
max-width: 67.5rem;
margin: 0 auto;
border: 2px solid var(--color-border);
}
[data-component="top"] {
padding: var(--space-12);
display: flex;
flex-direction: column;
align-items: start;
gap: var(--space-4);
[data-slot="logo"] {
height: 70px;
}
[data-slot="title"] {
font-size: var(--font-size-2xl);
text-transform: uppercase;
}
}
[data-component="cta"] {
height: var(--space-19);
border-top: 2px solid var(--color-border);
display: flex;
[data-slot="left"] {
display: flex;
padding: 0 var(--space-12);
text-transform: uppercase;
text-decoration: underline;
align-items: center;
justify-content: center;
text-underline-offset: var(--space-0-75);
border-right: 2px solid var(--color-border);
}
[data-slot="right"] {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-2-5);
padding: 0 var(--space-6);
}
[data-slot="command"] {
all: unset;
display: flex;
align-items: center;
cursor: pointer;
color: var(--color-text-secondary);
font-size: var(--font-size-lg);
font-family: var(--font-mono);
gap: var(--space-2);
}
[data-slot="highlight"] {
color: var(--color-text);
font-weight: 500;
}
}
[data-component="features"] {
border-top: 2px solid var(--color-border);
padding: var(--space-12);
[data-slot="list"] {
padding-left: var(--space-4);
margin: 0;
list-style: disc;
li {
margin-bottom: var(--space-4);
strong {
text-transform: uppercase;
font-weight: 600;
}
}
li:last-child {
margin-bottom: 0;
}
}
}
[data-component="install"] {
border-top: 2px solid var(--color-border);
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
@media (max-width: 40rem) {
grid-template-columns: 1fr;
grid-template-rows: auto;
}
}
[data-component="title"] {
letter-spacing: -0.03125rem;
text-transform: uppercase;
font-weight: 400;
font-size: var(--font-size-md);
flex-shrink: 0;
color: oklch(0.55 0.02 269.87);
}
[data-component="method"] {
padding: var(--space-4) var(--space-6);
display: flex;
flex-direction: column;
align-items: start;
gap: var(--space-3);
&:nth-child(2) {
border-left: 2px solid var(--color-border);
}
&:nth-child(3) {
border-top: 2px solid var(--color-border);
}
&:nth-child(4) {
border-top: 2px solid var(--color-border);
border-left: 2px solid var(--color-border);
}
[data-slot="button"] {
all: unset;
cursor: pointer;
display: flex;
align-items: center;
color: var(--color-text-secondary);
gap: var(--space-2);
strong {
color: var(--color-text);
font-weight: 500;
}
}
}
[data-component="screenshots"] {
border-top: 2px solid var(--color-border);
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0;
[data-slot="left"] {
padding: var(--space-8) var(--space-6);
display: flex;
flex-direction: column;
img {
width: 100%;
height: auto;
}
}
[data-slot="right"] {
display: grid;
grid-template-rows: 1fr 1fr;
border-left: 2px solid var(--color-border);
}
[data-slot="filler"] {
display: flex;
flex-grow: 1;
align-items: center;
justify-content: center;
}
[data-slot="cell"] {
padding: var(--space-8) var(--space-6);
display: flex;
flex-direction: column;
gap: var(--space-4);
&:nth-child(2) {
border-top: 2px solid var(--color-border);
}
img {
width: 80%;
height: auto;
}
}
}
[data-component="copy-status"] {
[data-slot="copy"] {
display: block;
width: var(--space-4);
height: var(--space-4);
color: var(--color-text-dimmed);
[data-copied] & {
display: none;
}
}
[data-slot="check"] {
display: none;
width: var(--space-4);
height: var(--space-4);
color: white;
[data-copied] & {
display: block;
}
}
}
[data-component="footer"] {
border-top: 2px solid var(--color-border);
display: grid;
grid-template-columns: 1fr 1fr 1fr;
font-size: var(--font-size-lg);
height: var(--space-20);
[data-slot="cell"] {
display: flex;
align-items: center;
justify-content: center;
border-right: 2px solid var(--color-border);
text-transform: uppercase;
&:last-child {
border-right: none;
}
}
}
}
-8
View File
@@ -1,8 +0,0 @@
html {
color-scheme: dark;
line-height: 1;
}
body {
font-family: var(--font-sans);
}
-90
View File
@@ -1,90 +0,0 @@
body {
--color-white: #ffffff;
--color-black: #000000;
}
[data-color-mode="dark"] {
/* OpenCode theme colors */
--color-bg: #0c0c0e;
--color-bg-surface: #161618;
--color-bg-elevated: #1c1c1f;
--color-text: #ffffff;
--color-text-muted: #a1a1a6;
--color-text-disabled: #68686f;
--color-accent: #007aff;
--color-accent-hover: #0056b3;
--color-accent-active: #004085;
--color-success: #30d158;
--color-warning: #ff9f0a;
--color-danger: #ff453a;
--color-border: #38383a;
--color-border-muted: #2c2c2e;
/* Button colors */
--color-primary: var(--color-accent);
--color-primary-hover: var(--color-accent-hover);
--color-primary-active: var(--color-accent-active);
--color-primary-text: #ffffff;
--color-danger: #ff453a;
--color-danger-hover: #d70015;
--color-danger-active: #a50011;
--color-danger-text: #ffffff;
--color-warning: #ff9f0a;
--color-warning-hover: #cc7f08;
--color-warning-active: #995f06;
--color-warning-text: #000000;
/* Surface colors */
--color-surface: var(--color-bg-surface);
--color-surface-hover: var(--color-bg-elevated);
--color-border: var(--color-border);
}
[data-color-mode="light"] {
/* OpenCode light theme colors */
--color-bg: #ffffff;
--color-bg-surface: #f5f5f7;
--color-bg-elevated: #ffffff;
--color-text: #1d1d1f;
--color-text-muted: #6e6e73;
--color-text-disabled: #86868b;
--color-accent: #007aff;
--color-accent-hover: #0056b3;
--color-accent-active: #004085;
--color-success: #30d158;
--color-warning: #ff9f0a;
--color-danger: #ff3b30;
--color-border: #d2d2d7;
--color-border-muted: #e5e5ea;
/* Button colors */
--color-primary: var(--color-accent);
--color-primary-hover: var(--color-accent-hover);
--color-primary-active: var(--color-accent-active);
--color-primary-text: #ffffff;
--color-danger: #ff3b30;
--color-danger-hover: #d70015;
--color-danger-active: #a50011;
--color-danger-text: #ffffff;
--color-warning: #ff9f0a;
--color-warning-hover: #cc7f08;
--color-warning-active: #995f06;
--color-warning-text: #000000;
/* Surface colors */
--color-surface: var(--color-bg-surface);
--color-surface-hover: var(--color-bg-elevated);
--color-border: var(--color-border);
}
@@ -1,66 +0,0 @@
CREATE TABLE "billing" (
"id" varchar(30) NOT NULL,
"workspace_id" varchar(30) NOT NULL,
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
"time_deleted" timestamp with time zone,
"customer_id" varchar(255),
"payment_method_id" varchar(255),
"payment_method_last4" varchar(4),
"balance" bigint NOT NULL,
"reload" boolean,
CONSTRAINT "billing_workspace_id_id_pk" PRIMARY KEY("workspace_id","id")
);
--> statement-breakpoint
CREATE TABLE "payment" (
"id" varchar(30) NOT NULL,
"workspace_id" varchar(30) NOT NULL,
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
"time_deleted" timestamp with time zone,
"customer_id" varchar(255),
"payment_id" varchar(255),
"amount" bigint NOT NULL,
CONSTRAINT "payment_workspace_id_id_pk" PRIMARY KEY("workspace_id","id")
);
--> statement-breakpoint
CREATE TABLE "usage" (
"id" varchar(30) NOT NULL,
"workspace_id" varchar(30) NOT NULL,
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
"time_deleted" timestamp with time zone,
"request_id" varchar(255),
"model" varchar(255) NOT NULL,
"input_tokens" integer NOT NULL,
"output_tokens" integer NOT NULL,
"reasoning_tokens" integer,
"cache_read_tokens" integer,
"cache_write_tokens" integer,
"cost" bigint NOT NULL,
CONSTRAINT "usage_workspace_id_id_pk" PRIMARY KEY("workspace_id","id")
);
--> statement-breakpoint
CREATE TABLE "user" (
"id" varchar(30) NOT NULL,
"workspace_id" varchar(30) NOT NULL,
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
"time_deleted" timestamp with time zone,
"email" text NOT NULL,
"name" varchar(255) NOT NULL,
"time_seen" timestamp with time zone,
"color" integer,
CONSTRAINT "user_workspace_id_id_pk" PRIMARY KEY("workspace_id","id")
);
--> statement-breakpoint
CREATE TABLE "workspace" (
"id" varchar(30) PRIMARY KEY NOT NULL,
"slug" varchar(255),
"name" varchar(255),
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
"time_deleted" timestamp with time zone
);
--> statement-breakpoint
ALTER TABLE "billing" ADD CONSTRAINT "billing_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "payment" ADD CONSTRAINT "payment_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "usage" ADD CONSTRAINT "usage_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "user" ADD CONSTRAINT "user_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
CREATE UNIQUE INDEX "user_email" ON "user" USING btree ("workspace_id","email");--> statement-breakpoint
CREATE UNIQUE INDEX "slug" ON "workspace" USING btree ("slug");
@@ -1,8 +0,0 @@
CREATE TABLE "account" (
"id" varchar(30) NOT NULL,
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
"time_deleted" timestamp with time zone,
"email" varchar(255) NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX "email" ON "account" USING btree ("email");
@@ -1,14 +0,0 @@
CREATE TABLE "key" (
"id" varchar(30) NOT NULL,
"workspace_id" varchar(30) NOT NULL,
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
"time_deleted" timestamp with time zone,
"user_id" text NOT NULL,
"name" varchar(255) NOT NULL,
"key" varchar(255) NOT NULL,
"time_used" timestamp with time zone,
CONSTRAINT "key_workspace_id_id_pk" PRIMARY KEY("workspace_id","id")
);
--> statement-breakpoint
ALTER TABLE "key" ADD CONSTRAINT "key_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
CREATE UNIQUE INDEX "global_key" ON "key" USING btree ("key");
@@ -1 +0,0 @@
ALTER TABLE "usage" DROP COLUMN "request_id";
@@ -1,461 +0,0 @@
{
"id": "9b5cec8c-8b59-4d7a-bb5c-76ade1c83d6f",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.billing": {
"name": "billing",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"time_created": {
"name": "time_created",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"billing_workspace_id_workspace_id_fk": {
"name": "billing_workspace_id_workspace_id_fk",
"tableFrom": "billing",
"tableTo": "workspace",
"columnsFrom": [
"workspace_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.payment": {
"name": "payment",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"time_created": {
"name": "time_created",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"payment_workspace_id_workspace_id_fk": {
"name": "payment_workspace_id_workspace_id_fk",
"tableFrom": "payment",
"tableTo": "workspace",
"columnsFrom": [
"workspace_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.usage": {
"name": "usage",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"time_created": {
"name": "time_created",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"request_id": {
"name": "request_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"input_tokens": {
"name": "input_tokens",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"output_tokens": {
"name": "output_tokens",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"cache_write_tokens": {
"name": "cache_write_tokens",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"usage_workspace_id_workspace_id_fk": {
"name": "usage_workspace_id_workspace_id_fk",
"tableFrom": "usage",
"tableTo": "workspace",
"columnsFrom": [
"workspace_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.user": {
"name": "user",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"time_created": {
"name": "time_created",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"time_seen": {
"name": "time_seen",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"color": {
"name": "color",
"type": "integer",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": [
{
"expression": "workspace_id",
"isExpression": false,
"asc": true,
"nulls": "last"
},
{
"expression": "email",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"user_workspace_id_workspace_id_fk": {
"name": "user_workspace_id_workspace_id_fk",
"tableFrom": "user",
"tableTo": "workspace",
"columnsFrom": [
"workspace_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.workspace": {
"name": "workspace",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": true,
"notNull": true
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"time_created": {
"name": "time_created",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": [
{
"expression": "slug",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}
@@ -1,515 +0,0 @@
{
"id": "bf9e9084-4073-4ecb-8e56-5610816c9589",
"prevId": "9b5cec8c-8b59-4d7a-bb5c-76ade1c83d6f",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.account": {
"name": "account",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"time_created": {
"name": "time_created",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"email": {
"name": "email",
"columns": [
{
"expression": "email",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.billing": {
"name": "billing",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"time_created": {
"name": "time_created",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"billing_workspace_id_workspace_id_fk": {
"name": "billing_workspace_id_workspace_id_fk",
"tableFrom": "billing",
"tableTo": "workspace",
"columnsFrom": [
"workspace_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.payment": {
"name": "payment",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"time_created": {
"name": "time_created",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"payment_workspace_id_workspace_id_fk": {
"name": "payment_workspace_id_workspace_id_fk",
"tableFrom": "payment",
"tableTo": "workspace",
"columnsFrom": [
"workspace_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.usage": {
"name": "usage",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"time_created": {
"name": "time_created",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"request_id": {
"name": "request_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"input_tokens": {
"name": "input_tokens",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"output_tokens": {
"name": "output_tokens",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"cache_write_tokens": {
"name": "cache_write_tokens",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"usage_workspace_id_workspace_id_fk": {
"name": "usage_workspace_id_workspace_id_fk",
"tableFrom": "usage",
"tableTo": "workspace",
"columnsFrom": [
"workspace_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.user": {
"name": "user",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true
},
"time_created": {
"name": "time_created",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"time_seen": {
"name": "time_seen",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"color": {
"name": "color",
"type": "integer",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": [
{
"expression": "workspace_id",
"isExpression": false,
"asc": true,
"nulls": "last"
},
{
"expression": "email",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"user_workspace_id_workspace_id_fk": {
"name": "user_workspace_id_workspace_id_fk",
"tableFrom": "user",
"tableTo": "workspace",
"columnsFrom": [
"workspace_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.workspace": {
"name": "workspace",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": true,
"notNull": true
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"time_created": {
"name": "time_created",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": [
{
"expression": "slug",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}
-34
View File
@@ -1,34 +0,0 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1754518198186,
"tag": "0000_amused_mojo",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1754609655262,
"tag": "0001_thankful_chat",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1754627626945,
"tag": "0002_stale_jackal",
"breakpoints": true
},
{
"idx": 3,
"version": "7",
"when": 1754672464106,
"tag": "0003_tranquil_spencer_smythe",
"breakpoints": true
}
]
}
-23
View File
@@ -1,23 +0,0 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode/cloud-core",
"version": "0.5.10",
"private": true,
"type": "module",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"drizzle-orm": "0.41.0",
"postgres": "3.4.7",
"stripe": "18.0.0",
"ulid": "3.0.0"
},
"exports": {
"./*": "./src/*"
},
"scripts": {
"db": "sst shell drizzle-kit"
},
"devDependencies": {
"drizzle-kit": "0.30.5"
}
}
-71
View File
@@ -1,71 +0,0 @@
import { Resource } from "sst"
import { Stripe } from "stripe"
import { Database, eq, sql } from "./drizzle"
import { BillingTable, UsageTable } from "./schema/billing.sql"
import { Actor } from "./actor"
import { fn } from "./util/fn"
import { z } from "zod"
import { Identifier } from "./identifier"
import { centsToMicroCents } from "./util/price"
export namespace Billing {
export const stripe = () =>
new Stripe(Resource.STRIPE_SECRET_KEY.value, {
apiVersion: "2025-03-31.basil",
})
export const get = async () => {
return Database.use(async (tx) =>
tx
.select({
customerID: BillingTable.customerID,
paymentMethodID: BillingTable.paymentMethodID,
balance: BillingTable.balance,
reload: BillingTable.reload,
})
.from(BillingTable)
.where(eq(BillingTable.workspaceID, Actor.workspace()))
.then((r) => r[0]),
)
}
export const consume = fn(
z.object({
requestID: z.string().optional(),
model: z.string(),
inputTokens: z.number(),
outputTokens: z.number(),
reasoningTokens: z.number().optional(),
cacheReadTokens: z.number().optional(),
cacheWriteTokens: z.number().optional(),
costInCents: z.number(),
}),
async (input) => {
const workspaceID = Actor.workspace()
const cost = centsToMicroCents(input.costInCents)
return await Database.transaction(async (tx) => {
await tx.insert(UsageTable).values({
workspaceID,
id: Identifier.create("usage"),
requestID: input.requestID,
model: input.model,
inputTokens: input.inputTokens,
outputTokens: input.outputTokens,
reasoningTokens: input.reasoningTokens,
cacheReadTokens: input.cacheReadTokens,
cacheWriteTokens: input.cacheWriteTokens,
cost,
})
const [updated] = await tx
.update(BillingTable)
.set({
balance: sql`${BillingTable.balance} - ${cost}`,
})
.where(eq(BillingTable.workspaceID, workspaceID))
.returning()
return updated.balance
})
},
)
}
-45
View File
@@ -1,45 +0,0 @@
import { bigint, boolean, integer, pgTable, varchar } from "drizzle-orm/pg-core"
import { timestamps, workspaceColumns } from "../drizzle/types"
import { workspaceIndexes } from "./workspace.sql"
export const BillingTable = pgTable(
"billing",
{
...workspaceColumns,
...timestamps,
customerID: varchar("customer_id", { length: 255 }),
paymentMethodID: varchar("payment_method_id", { length: 255 }),
paymentMethodLast4: varchar("payment_method_last4", { length: 4 }),
balance: bigint("balance", { mode: "number" }).notNull(),
reload: boolean("reload"),
},
(table) => [...workspaceIndexes(table)],
)
export const PaymentTable = pgTable(
"payment",
{
...workspaceColumns,
...timestamps,
customerID: varchar("customer_id", { length: 255 }),
paymentID: varchar("payment_id", { length: 255 }),
amount: bigint("amount", { mode: "number" }).notNull(),
},
(table) => [...workspaceIndexes(table)],
)
export const UsageTable = pgTable(
"usage",
{
...workspaceColumns,
...timestamps,
model: varchar("model", { length: 255 }).notNull(),
inputTokens: integer("input_tokens").notNull(),
outputTokens: integer("output_tokens").notNull(),
reasoningTokens: integer("reasoning_tokens"),
cacheReadTokens: integer("cache_read_tokens"),
cacheWriteTokens: integer("cache_write_tokens"),
cost: bigint("cost", { mode: "number" }).notNull(),
},
(table) => [...workspaceIndexes(table)],
)
-16
View File
@@ -1,16 +0,0 @@
import { text, pgTable, uniqueIndex, varchar, integer } from "drizzle-orm/pg-core"
import { timestamps, utc, workspaceColumns } from "../drizzle/types"
import { workspaceIndexes } from "./workspace.sql"
export const UserTable = pgTable(
"user",
{
...workspaceColumns,
...timestamps,
email: text("email").notNull(),
name: varchar("name", { length: 255 }).notNull(),
timeSeen: utc("time_seen"),
color: integer("color"),
},
(table) => [...workspaceIndexes(table), uniqueIndex("user_email").on(table.workspaceID, table.email)],
)
-14
View File
@@ -1,14 +0,0 @@
import { z } from "zod"
export function fn<T extends z.ZodType, Result>(
schema: T,
cb: (input: z.output<T>) => Result,
) {
const result = (input: z.input<T>) => {
const parsed = schema.parse(input)
return cb(parsed)
}
result.force = (input: z.input<T>) => cb(input)
result.schema = schema
return result
}
-48
View File
@@ -1,48 +0,0 @@
import { z } from "zod"
import { fn } from "./util/fn"
import { centsToMicroCents } from "./util/price"
import { Actor } from "./actor"
import { Database, eq } from "./drizzle"
import { Identifier } from "./identifier"
import { UserTable } from "./schema/user.sql"
import { BillingTable } from "./schema/billing.sql"
import { WorkspaceTable } from "./schema/workspace.sql"
export namespace Workspace {
export const create = fn(z.void(), async () => {
const account = Actor.assert("account")
const workspaceID = Identifier.create("workspace")
await Database.transaction(async (tx) => {
await tx.insert(WorkspaceTable).values({
id: workspaceID,
})
await tx.insert(UserTable).values({
workspaceID,
id: Identifier.create("user"),
email: account.properties.email,
name: "",
})
await tx.insert(BillingTable).values({
workspaceID,
id: Identifier.create("billing"),
balance: centsToMicroCents(100),
})
})
return workspaceID
})
export async function list() {
const account = Actor.assert("account")
return Database.use(async (tx) => {
return tx
.select({
id: WorkspaceTable.id,
slug: WorkspaceTable.slug,
name: WorkspaceTable.name,
})
.from(UserTable)
.innerJoin(WorkspaceTable, eq(UserTable.workspaceID, WorkspaceTable.id))
.where(eq(UserTable.email, account.properties.email))
})
}
}
-909
View File
@@ -1,909 +0,0 @@
import { z } from "zod"
import { Hono, MiddlewareHandler } from "hono"
import { cors } from "hono/cors"
import { HTTPException } from "hono/http-exception"
import { zValidator } from "@hono/zod-validator"
import { Resource } from "sst"
import { type ProviderMetadata, type LanguageModelUsage, generateText, streamText } from "ai"
import { createAnthropic } from "@ai-sdk/anthropic"
import { createOpenAI } from "@ai-sdk/openai"
import { createOpenAICompatible } from "@ai-sdk/openai-compatible"
import type { LanguageModelV2Prompt } from "@ai-sdk/provider"
import { type ChatCompletionCreateParamsBase } from "openai/resources/chat/completions"
import { Actor } from "@opencode/cloud-core/actor.js"
import { and, Database, eq, sql } from "@opencode/cloud-core/drizzle/index.js"
import { UserTable } from "@opencode/cloud-core/schema/user.sql.js"
import { KeyTable } from "@opencode/cloud-core/schema/key.sql.js"
import { createClient } from "@openauthjs/openauth/client"
import { Log } from "@opencode/cloud-core/util/log.js"
import { Billing } from "@opencode/cloud-core/billing.js"
import { Workspace } from "@opencode/cloud-core/workspace.js"
import { BillingTable, PaymentTable, UsageTable } from "@opencode/cloud-core/schema/billing.sql.js"
import { centsToMicroCents } from "@opencode/cloud-core/util/price.js"
import { Identifier } from "../../core/src/identifier"
type Env = {}
let _client: ReturnType<typeof createClient>
const client = () => {
if (_client) return _client
_client = createClient({
clientID: "api",
issuer: Resource.AUTH_API_URL.value,
})
return _client
}
const SUPPORTED_MODELS = {
"anthropic/claude-sonnet-4": {
input: 0.0000015,
output: 0.000006,
reasoning: 0.0000015,
cacheRead: 0.0000001,
cacheWrite: 0.0000001,
model: () =>
createAnthropic({
apiKey: Resource.ANTHROPIC_API_KEY.value,
})("claude-sonnet-4-20250514"),
},
"openai/gpt-4.1": {
input: 0.0000015,
output: 0.000006,
reasoning: 0.0000015,
cacheRead: 0.0000001,
cacheWrite: 0.0000001,
model: () =>
createOpenAI({
apiKey: Resource.OPENAI_API_KEY.value,
})("gpt-4.1"),
},
"zhipuai/glm-4.5-flash": {
input: 0,
output: 0,
reasoning: 0,
cacheRead: 0,
cacheWrite: 0,
model: () =>
createOpenAICompatible({
name: "Zhipu AI",
baseURL: "https://api.z.ai/api/paas/v4",
apiKey: Resource.ZHIPU_API_KEY.value,
})("glm-4.5-flash"),
},
}
const log = Log.create({
namespace: "api",
})
const GatewayAuth: MiddlewareHandler = async (c, next) => {
const authHeader = c.req.header("authorization")
if (!authHeader || !authHeader.startsWith("Bearer ")) {
return c.json(
{
error: {
message: "Missing API key.",
type: "invalid_request_error",
param: null,
code: "unauthorized",
},
},
401,
)
}
const apiKey = authHeader.split(" ")[1]
// Check against KeyTable
const keyRecord = await Database.use((tx) =>
tx
.select({
id: KeyTable.id,
workspaceID: KeyTable.workspaceID,
})
.from(KeyTable)
.where(eq(KeyTable.key, apiKey))
.then((rows) => rows[0]),
)
if (!keyRecord) {
return c.json(
{
error: {
message: "Invalid API key.",
type: "invalid_request_error",
param: null,
code: "unauthorized",
},
},
401,
)
}
c.set("keyRecord", keyRecord)
await next()
}
const RestAuth: MiddlewareHandler = async (c, next) => {
const authorization = c.req.header("authorization")
if (!authorization) {
return Actor.provide("public", {}, next)
}
const token = authorization.split(" ")[1]
if (!token)
throw new HTTPException(403, {
message: "Bearer token is required.",
})
const verified = await client().verify(token)
if (verified.err) {
throw new HTTPException(403, {
message: "Invalid token.",
})
}
let subject = verified.subject as Actor.Info
if (subject.type === "account") {
const workspaceID = c.req.header("x-opencode-workspace")
const email = subject.properties.email
if (workspaceID) {
const user = await Database.use((tx) =>
tx
.select({
id: UserTable.id,
workspaceID: UserTable.workspaceID,
email: UserTable.email,
})
.from(UserTable)
.where(and(eq(UserTable.email, email), eq(UserTable.workspaceID, workspaceID)))
.then((rows) => rows[0]),
)
if (!user)
throw new HTTPException(403, {
message: "You do not have access to this workspace.",
})
subject = {
type: "user",
properties: {
userID: user.id,
workspaceID: workspaceID,
email: user.email,
},
}
}
}
await Actor.provide(subject.type, subject.properties, next)
}
const app = new Hono<{ Bindings: Env; Variables: { keyRecord?: { id: string; workspaceID: string } } }>()
.get("/", (c) => c.text("Hello, world!"))
.post("/v1/chat/completions", GatewayAuth, async (c) => {
const keyRecord = c.get("keyRecord")!
return await Actor.provide("system", { workspaceID: keyRecord.workspaceID }, async () => {
try {
// Check balance
const customer = await Billing.get()
if (customer.balance <= 0) {
return c.json(
{
error: {
message: "Insufficient balance",
type: "insufficient_quota",
param: null,
code: "insufficient_quota",
},
},
401,
)
}
const body = await c.req.json<ChatCompletionCreateParamsBase>()
const model = SUPPORTED_MODELS[body.model as keyof typeof SUPPORTED_MODELS]?.model()
if (!model) throw new Error(`Unsupported model: ${body.model}`)
const requestBody = transformOpenAIRequestToAiSDK()
return body.stream ? await handleStream() : await handleGenerate()
async function handleStream() {
const result = await model.doStream({
...requestBody,
})
const encoder = new TextEncoder()
const stream = new ReadableStream({
async start(controller) {
const id = `chatcmpl-${Date.now()}`
const created = Math.floor(Date.now() / 1000)
try {
for await (const chunk of result.stream) {
console.log("!!! CHUNK !!! : " + chunk.type)
switch (chunk.type) {
case "text-delta": {
const data = {
id,
object: "chat.completion.chunk",
created,
model: body.model,
choices: [
{
index: 0,
delta: {
content: chunk.delta,
},
finish_reason: null,
},
],
}
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`))
break
}
case "reasoning-delta": {
const data = {
id,
object: "chat.completion.chunk",
created,
model: body.model,
choices: [
{
index: 0,
delta: {
reasoning_content: chunk.delta,
},
finish_reason: null,
},
],
}
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`))
break
}
case "tool-call": {
const data = {
id,
object: "chat.completion.chunk",
created,
model: body.model,
choices: [
{
index: 0,
delta: {
tool_calls: [
{
index: 0,
id: chunk.toolCallId,
type: "function",
function: {
name: chunk.toolName,
arguments: chunk.input,
},
},
],
},
finish_reason: null,
},
],
}
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`))
break
}
case "error": {
const data = {
id,
object: "chat.completion.chunk",
created,
model: body.model,
choices: [
{
index: 0,
delta: {},
finish_reason: "stop",
},
],
error: {
message: typeof chunk.error === "string" ? chunk.error : chunk.error,
type: "server_error",
},
}
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`))
controller.enqueue(encoder.encode("data: [DONE]\n\n"))
controller.close()
break
}
case "finish": {
const data = {
id,
object: "chat.completion.chunk",
created,
model: body.model,
choices: [
{
index: 0,
delta: {},
finish_reason:
{
stop: "stop",
length: "length",
"content-filter": "content_filter",
"tool-calls": "tool_calls",
error: "stop",
other: "stop",
unknown: "stop",
}[chunk.finishReason] || "stop",
},
],
usage: {
prompt_tokens: chunk.usage.inputTokens,
completion_tokens: chunk.usage.outputTokens,
total_tokens: chunk.usage.totalTokens,
completion_tokens_details: {
reasoning_tokens: chunk.usage.reasoningTokens,
},
prompt_tokens_details: {
cached_tokens: chunk.usage.cachedInputTokens,
},
},
}
await trackUsage(body.model, chunk.usage, chunk.providerMetadata)
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`))
controller.enqueue(encoder.encode("data: [DONE]\n\n"))
controller.close()
break
}
//case "stream-start":
//case "response-metadata":
case "text-start":
case "text-end":
case "reasoning-start":
case "reasoning-end":
case "tool-input-start":
case "tool-input-delta":
case "tool-input-end":
case "raw":
default:
// Log unknown chunk types for debugging
console.warn(`Unknown chunk type: ${(chunk as any).type}`)
break
}
}
} catch (error) {
controller.error(error)
}
},
})
return new Response(stream, {
headers: {
"Content-Type": "text/plain; charset=utf-8",
"Cache-Control": "no-cache",
Connection: "keep-alive",
},
})
}
async function handleGenerate() {
const response = await model.doGenerate({
...requestBody,
})
await trackUsage(body.model, response.usage, response.providerMetadata)
return c.json({
id: `chatcmpl-${Date.now()}`,
object: "chat.completion" as const,
created: Math.floor(Date.now() / 1000),
model: body.model,
choices: [
{
index: 0,
message: {
role: "assistant" as const,
content: response.content?.find((c) => c.type === "text")?.text ?? "",
reasoning_content: response.content?.find((c) => c.type === "reasoning")?.text,
tool_calls: response.content
?.filter((c) => c.type === "tool-call")
.map((toolCall) => ({
id: toolCall.toolCallId,
type: "function" as const,
function: {
name: toolCall.toolName,
arguments: toolCall.input,
},
})),
},
finish_reason:
(
{
stop: "stop",
length: "length",
"content-filter": "content_filter",
"tool-calls": "tool_calls",
error: "stop",
other: "stop",
unknown: "stop",
} as const
)[response.finishReason] || "stop",
},
],
usage: {
prompt_tokens: response.usage?.inputTokens,
completion_tokens: response.usage?.outputTokens,
total_tokens: response.usage?.totalTokens,
completion_tokens_details: {
reasoning_tokens: response.usage?.reasoningTokens,
},
prompt_tokens_details: {
cached_tokens: response.usage?.cachedInputTokens,
},
},
})
}
function transformOpenAIRequestToAiSDK() {
const prompt = transformMessages()
const tools = transformTools()
return {
prompt,
maxOutputTokens: body.max_tokens ?? body.max_completion_tokens ?? undefined,
temperature: body.temperature ?? undefined,
topP: body.top_p ?? undefined,
frequencyPenalty: body.frequency_penalty ?? undefined,
presencePenalty: body.presence_penalty ?? undefined,
providerOptions: body.reasoning_effort
? {
anthropic: {
reasoningEffort: body.reasoning_effort,
},
}
: undefined,
stopSequences: (typeof body.stop === "string" ? [body.stop] : body.stop) ?? undefined,
responseFormat: (() => {
if (!body.response_format) return { type: "text" as const }
if (body.response_format.type === "json_schema")
return {
type: "json" as const,
schema: body.response_format.json_schema.schema,
name: body.response_format.json_schema.name,
description: body.response_format.json_schema.description,
}
if (body.response_format.type === "json_object") return { type: "json" as const }
throw new Error("Unsupported response format")
})(),
seed: body.seed ?? undefined,
tools: tools.tools,
toolChoice: tools.toolChoice,
}
function transformTools() {
const { tools, tool_choice } = body
if (!tools || tools.length === 0) {
return { tools: undefined, toolChoice: undefined }
}
const aiSdkTools = tools.map((tool) => {
return {
type: tool.type,
name: tool.function.name,
description: tool.function.description,
inputSchema: tool.function.parameters!,
}
})
let aiSdkToolChoice
if (tool_choice == null) {
aiSdkToolChoice = undefined
} else if (tool_choice === "auto") {
aiSdkToolChoice = { type: "auto" as const }
} else if (tool_choice === "none") {
aiSdkToolChoice = { type: "none" as const }
} else if (tool_choice === "required") {
aiSdkToolChoice = { type: "required" as const }
} else if (tool_choice.type === "function") {
aiSdkToolChoice = {
type: "tool" as const,
toolName: tool_choice.function.name,
}
}
return { tools: aiSdkTools, toolChoice: aiSdkToolChoice }
}
function transformMessages() {
const { messages } = body
const prompt: LanguageModelV2Prompt = []
for (const message of messages) {
switch (message.role) {
case "system": {
prompt.push({
role: "system",
content: message.content as string,
})
break
}
case "user": {
if (typeof message.content === "string") {
prompt.push({
role: "user",
content: [{ type: "text", text: message.content }],
})
} else {
const content = message.content.map((part) => {
switch (part.type) {
case "text":
return { type: "text" as const, text: part.text }
case "image_url":
return {
type: "file" as const,
mediaType: "image/jpeg" as const,
data: part.image_url.url,
}
default:
throw new Error(`Unsupported content part type: ${(part as any).type}`)
}
})
prompt.push({
role: "user",
content,
})
}
break
}
case "assistant": {
const content: Array<
| { type: "text"; text: string }
| {
type: "tool-call"
toolCallId: string
toolName: string
input: any
}
> = []
if (message.content) {
content.push({
type: "text",
text: message.content as string,
})
}
if (message.tool_calls) {
for (const toolCall of message.tool_calls) {
content.push({
type: "tool-call",
toolCallId: toolCall.id,
toolName: toolCall.function.name,
input: JSON.parse(toolCall.function.arguments),
})
}
}
prompt.push({
role: "assistant",
content,
})
break
}
case "tool": {
prompt.push({
role: "tool",
content: [
{
type: "tool-result",
toolName: "placeholder",
toolCallId: message.tool_call_id,
output: {
type: "text",
value: message.content as string,
},
},
],
})
break
}
default: {
throw new Error(`Unsupported message role: ${message.role}`)
}
}
}
return prompt
}
}
async function trackUsage(model: string, usage: LanguageModelUsage, providerMetadata?: ProviderMetadata) {
const modelData = SUPPORTED_MODELS[model as keyof typeof SUPPORTED_MODELS]
if (!modelData) throw new Error(`Unsupported model: ${model}`)
const inputTokens = usage.inputTokens ?? 0
const outputTokens = usage.outputTokens ?? 0
const reasoningTokens = usage.reasoningTokens ?? 0
const cacheReadTokens = usage.cachedInputTokens ?? 0
const cacheWriteTokens =
providerMetadata?.["anthropic"]?.["cacheCreationInputTokens"] ??
// @ts-expect-error
providerMetadata?.["bedrock"]?.["usage"]?.["cacheWriteInputTokens"] ??
0
const inputCost = modelData.input * inputTokens
const outputCost = modelData.output * outputTokens
const reasoningCost = modelData.reasoning * reasoningTokens
const cacheReadCost = modelData.cacheRead * cacheReadTokens
const cacheWriteCost = modelData.cacheWrite * cacheWriteTokens
const costInCents = (inputCost + outputCost + reasoningCost + cacheReadCost + cacheWriteCost) * 100
await Billing.consume({
model,
inputTokens,
outputTokens,
reasoningTokens,
cacheReadTokens,
cacheWriteTokens,
costInCents,
})
await Database.use((tx) =>
tx
.update(KeyTable)
.set({ timeUsed: sql`now()` })
.where(eq(KeyTable.id, keyRecord.id)),
)
}
} catch (error: any) {
return c.json({ error: { message: error.message } }, 500)
}
})
})
.use("/*", cors())
.use(RestAuth)
.get("/rest/account", async (c) => {
const account = Actor.assert("account")
let workspaces = await Workspace.list()
if (workspaces.length === 0) {
await Workspace.create()
workspaces = await Workspace.list()
}
return c.json({
id: account.properties.accountID,
email: account.properties.email,
workspaces,
})
})
.get("/billing/info", async (c) => {
const billing = await Billing.get()
const payments = await Database.use((tx) =>
tx
.select()
.from(PaymentTable)
.where(eq(PaymentTable.workspaceID, Actor.workspace()))
.orderBy(sql`${PaymentTable.timeCreated} DESC`)
.limit(100),
)
const usage = await Database.use((tx) =>
tx
.select()
.from(UsageTable)
.where(eq(UsageTable.workspaceID, Actor.workspace()))
.orderBy(sql`${UsageTable.timeCreated} DESC`)
.limit(100),
)
return c.json({ billing, payments, usage })
})
.post(
"/billing/checkout",
zValidator(
"json",
z.custom<{
success_url: string
cancel_url: string
}>(),
),
async (c) => {
const account = Actor.assert("user")
const body = await c.req.json()
const customer = await Billing.get()
const session = await Billing.stripe().checkout.sessions.create({
mode: "payment",
line_items: [
{
price_data: {
currency: "usd",
product_data: {
name: "opencode credits",
},
unit_amount: 2000, // $20 minimum
},
quantity: 1,
},
],
payment_intent_data: {
setup_future_usage: "on_session",
},
...(customer.customerID
? { customer: customer.customerID }
: {
customer_email: account.properties.email,
customer_creation: "always",
}),
metadata: {
workspaceID: Actor.workspace(),
},
currency: "usd",
payment_method_types: ["card"],
success_url: body.success_url,
cancel_url: body.cancel_url,
})
return c.json({
url: session.url,
})
},
)
.post("/billing/portal", async (c) => {
const body = await c.req.json()
const customer = await Billing.get()
if (!customer?.customerID) {
throw new Error("No stripe customer ID")
}
const session = await Billing.stripe().billingPortal.sessions.create({
customer: customer.customerID,
return_url: body.return_url,
})
return c.json({
url: session.url,
})
})
.post("/stripe/webhook", async (c) => {
const body = await Billing.stripe().webhooks.constructEventAsync(
await c.req.text(),
c.req.header("stripe-signature")!,
Resource.STRIPE_WEBHOOK_SECRET.value,
)
console.log(body.type, JSON.stringify(body, null, 2))
if (body.type === "checkout.session.completed") {
const workspaceID = body.data.object.metadata?.workspaceID
const customerID = body.data.object.customer as string
const paymentID = body.data.object.payment_intent as string
const amount = body.data.object.amount_total
if (!workspaceID) throw new Error("Workspace ID not found")
if (!customerID) throw new Error("Customer ID not found")
if (!amount) throw new Error("Amount not found")
if (!paymentID) throw new Error("Payment ID not found")
await Actor.provide("system", { workspaceID }, async () => {
const customer = await Billing.get()
if (customer?.customerID && customer.customerID !== customerID) throw new Error("Customer ID mismatch")
// set customer metadata
if (!customer?.customerID) {
await Billing.stripe().customers.update(customerID, {
metadata: {
workspaceID,
},
})
}
// get payment method for the payment intent
const paymentIntent = await Billing.stripe().paymentIntents.retrieve(paymentID, {
expand: ["payment_method"],
})
const paymentMethod = paymentIntent.payment_method
if (!paymentMethod || typeof paymentMethod === "string") throw new Error("Payment method not expanded")
await Database.transaction(async (tx) => {
await tx
.update(BillingTable)
.set({
balance: sql`${BillingTable.balance} + ${centsToMicroCents(amount)}`,
customerID,
paymentMethodID: paymentMethod.id,
paymentMethodLast4: paymentMethod.card!.last4,
})
.where(eq(BillingTable.workspaceID, workspaceID))
await tx.insert(PaymentTable).values({
workspaceID,
id: Identifier.create("payment"),
amount: centsToMicroCents(amount),
paymentID,
customerID,
})
})
})
}
console.log("finished handling")
return c.json("ok", 200)
})
.get("/keys", async (c) => {
const user = Actor.assert("user")
const keys = await Database.use((tx) =>
tx
.select({
id: KeyTable.id,
name: KeyTable.name,
key: KeyTable.key,
userID: KeyTable.userID,
timeCreated: KeyTable.timeCreated,
timeUsed: KeyTable.timeUsed,
})
.from(KeyTable)
.where(eq(KeyTable.workspaceID, user.properties.workspaceID))
.orderBy(sql`${KeyTable.timeCreated} DESC`),
)
return c.json({ keys })
})
.post("/keys", zValidator("json", z.object({ name: z.string().min(1).max(255) })), async (c) => {
const user = Actor.assert("user")
const { name } = c.req.valid("json")
// Generate secret key: sk- + 64 random characters (upper, lower, numbers)
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
let randomPart = ""
for (let i = 0; i < 64; i++) {
randomPart += chars.charAt(Math.floor(Math.random() * chars.length))
}
const secretKey = `sk-${randomPart}`
const keyRecord = await Database.use((tx) =>
tx
.insert(KeyTable)
.values({
id: Identifier.create("key"),
workspaceID: user.properties.workspaceID,
userID: user.properties.userID,
name,
key: secretKey,
timeUsed: null,
})
.returning(),
)
return c.json({
key: secretKey,
id: keyRecord[0].id,
name: keyRecord[0].name,
created: keyRecord[0].timeCreated,
})
})
.delete("/keys/:id", async (c) => {
const user = Actor.assert("user")
const keyId = c.req.param("id")
const result = await Database.use((tx) =>
tx
.delete(KeyTable)
.where(and(eq(KeyTable.id, keyId), eq(KeyTable.workspaceID, user.properties.workspaceID)))
.returning({ id: KeyTable.id }),
)
if (result.length === 0) {
return c.json({ error: "Key not found" }, 404)
}
return c.json({ success: true, id: result[0].id })
})
.all("*", (c) => c.text("Not Found"))
export type ApiType = typeof app
export default app
-2
View File
@@ -1,2 +0,0 @@
node_modules
dist
-38
View File
@@ -1,38 +0,0 @@
<!doctype html>
<html lang="en" data-color-mode="dark">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>OpenControl</title>
<link rel="shortcut icon" type="image/ico" href="/favicon.ico" />
<link rel="icon" href="/favicon.ico" sizes="48x48">
<link rel="icon" href="/favicon.svg" media="(prefers-color-scheme: light)">
<link rel="icon" href="/favicon-dark.svg" media="(prefers-color-scheme: dark)">
<link rel="shortcut icon" href="/favicon.svg" type="image/svg+xml">
<meta property="twitter:image" content="%BASE_URL%/social-share.png">
<meta property="og:title" content="OpenControl">
<meta property="og:url" content="%BASE_URL%">
<meta property="og:locale" content="en">
<meta property="og:description" content="Control your infrastructure with AI.">
<meta property="og:site_name" content="OpenControl">
<meta name="twitter:card" content="summary_large_image">
<meta name="description" content="Control your infrastructure with AI.">
<meta property="og:image" content="%BASE_URL%/social-share.png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600;700&family=Rubik:wght@300..900&display=swap" rel="stylesheet">
<!--ssr-head-->
<!--ssr-assets-->
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root">
<!--ssr-outlet-->
</div>
<script type="module" src="/src/entry-client.tsx"></script>
</body>
</html>
-29
View File
@@ -1,29 +0,0 @@
0 info it worked if it ends with ok
1 verbose cli [
1 verbose cli '/usr/local/bin/node',
1 verbose cli '/Users/frank/Sites/opencode/node_modules/.bin/npm',
1 verbose cli 'run',
1 verbose cli 'dev'
1 verbose cli ]
2 info using npm@2.15.12
3 info using node@v20.18.1
4 verbose stack Error: Invalid name: "@opencode/cloud/web"
4 verbose stack at ensureValidName (/Users/frank/Sites/opencode/node_modules/npm/node_modules/normalize-package-data/lib/fixer.js:336:15)
4 verbose stack at Object.fixNameField (/Users/frank/Sites/opencode/node_modules/npm/node_modules/normalize-package-data/lib/fixer.js:215:5)
4 verbose stack at /Users/frank/Sites/opencode/node_modules/npm/node_modules/normalize-package-data/lib/normalize.js:32:38
4 verbose stack at Array.forEach (<anonymous>)
4 verbose stack at normalize (/Users/frank/Sites/opencode/node_modules/npm/node_modules/normalize-package-data/lib/normalize.js:31:15)
4 verbose stack at final (/Users/frank/Sites/opencode/node_modules/npm/node_modules/read-package-json/read-json.js:349:5)
4 verbose stack at then (/Users/frank/Sites/opencode/node_modules/npm/node_modules/read-package-json/read-json.js:124:5)
4 verbose stack at ReadFileContext.<anonymous> (/Users/frank/Sites/opencode/node_modules/npm/node_modules/read-package-json/read-json.js:295:20)
4 verbose stack at ReadFileContext.callback (/Users/frank/Sites/opencode/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:78:16)
4 verbose stack at FSReqCallback.readFileAfterOpen [as oncomplete] (node:fs:299:13)
5 verbose cwd /Users/frank/Sites/opencode/cloud/web
6 error Darwin 24.5.0
7 error argv "/usr/local/bin/node" "/Users/frank/Sites/opencode/node_modules/.bin/npm" "run" "dev"
8 error node v20.18.1
9 error npm v2.15.12
10 error Invalid name: "@opencode/cloud/web"
11 error If you need help, you may report this error at:
11 error <https://github.com/npm/npm/issues>
12 verbose exit [ 1, true ]
-32
View File
@@ -1,32 +0,0 @@
{
"name": "@opencode/cloud-web",
"version": "0.5.10",
"private": true,
"description": "",
"type": "module",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "bun build:server && bun build:client",
"build:client": "vite build --outDir dist/client",
"build:server": "vite build --ssr src/entry-server.tsx --outDir dist/server",
"serve": "vite preview",
"sst:dev": "bun sst shell --target Console -- bun dev"
},
"license": "MIT",
"devDependencies": {
"typescript": "catalog:",
"vite": "6.2.2",
"vite-plugin-pages": "0.32.5",
"vite-plugin-solid": "2.11.6"
},
"dependencies": {
"@kobalte/core": "0.13.9",
"@openauthjs/solid": "0.0.0-20250322224806",
"@solid-primitives/storage": "4.3.1",
"@solidjs/meta": "0.29.4",
"@solidjs/router": "0.15.3",
"solid-js": "1.9.5",
"solid-list": "0.3.0"
}
}
-3
View File
@@ -1,3 +0,0 @@
<svg width="28" height="32" viewBox="0 0 28 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 31.5L0 23.6873V7.81266L14 0L28 7.81266V23.6873L14 31.5ZM14 28.4664L25.3456 22.0251V9.47493L14 2.99209L2.65443 9.47493V22.0251L14 28.4664ZM13.9572 24.6016C12.2732 24.6016 10.7176 24.1999 9.29052 23.3964C7.89195 22.593 6.7788 21.5125 5.95107 20.155C5.12334 18.7698 4.70948 17.2599 4.70948 15.6253C4.70948 13.9908 5.12334 12.4947 5.95107 11.1372C6.7788 9.77968 7.89195 8.69921 9.29052 7.89578C10.7176 7.06464 12.2732 6.64908 13.9572 6.64908C15.6412 6.64908 17.1825 7.06464 18.581 7.89578C19.9796 8.69921 21.0928 9.77968 21.9205 11.1372C22.7768 12.4947 23.2049 13.9908 23.2049 15.6253C23.2049 17.2599 22.791 18.7559 21.9633 20.1135C21.1356 21.471 20.0224 22.5653 18.6239 23.3964C17.2253 24.1999 15.6697 24.6016 13.9572 24.6016ZM13.9572 22.2744C15.213 22.2744 16.3547 21.9697 17.3823 21.3602C18.4098 20.7507 19.2375 19.9472 19.8654 18.9499C20.4934 17.9248 20.8073 16.8166 20.8073 15.6253C20.8073 14.4063 20.4934 13.2982 19.8654 12.3008C19.2375 11.3034 18.4098 10.5 17.3823 9.8905C16.3547 9.281 15.213 8.97625 13.9572 8.97625C12.7299 8.97625 11.5882 9.281 10.5321 9.8905C9.50459 10.5 8.67686 11.3034 8.04893 12.3008C7.421 13.2982 7.10703 14.4063 7.10703 15.6253C7.10703 16.8166 7.421 17.9248 8.04893 18.9499C8.67686 19.9472 9.50459 20.7507 10.5321 21.3602C11.5882 21.9697 12.7299 22.2744 13.9572 22.2744Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

-3
View File
@@ -1,3 +0,0 @@
<svg width="28" height="32" viewBox="0 0 28 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 31.5L0 23.6873V7.81266L14 0L28 7.81266V23.6873L14 31.5ZM14 28.4664L25.3456 22.0251V9.47493L14 2.99209L2.65443 9.47493V22.0251L14 28.4664ZM13.9572 24.6016C12.2732 24.6016 10.7176 24.1999 9.29052 23.3964C7.89195 22.593 6.7788 21.5125 5.95107 20.155C5.12334 18.7698 4.70948 17.2599 4.70948 15.6253C4.70948 13.9908 5.12334 12.4947 5.95107 11.1372C6.7788 9.77968 7.89195 8.69921 9.29052 7.89578C10.7176 7.06464 12.2732 6.64908 13.9572 6.64908C15.6412 6.64908 17.1825 7.06464 18.581 7.89578C19.9796 8.69921 21.0928 9.77968 21.9205 11.1372C22.7768 12.4947 23.2049 13.9908 23.2049 15.6253C23.2049 17.2599 22.791 18.7559 21.9633 20.1135C21.1356 21.471 20.0224 22.5653 18.6239 23.3964C17.2253 24.1999 15.6697 24.6016 13.9572 24.6016ZM13.9572 22.2744C15.213 22.2744 16.3547 21.9697 17.3823 21.3602C18.4098 20.7507 19.2375 19.9472 19.8654 18.9499C20.4934 17.9248 20.8073 16.8166 20.8073 15.6253C20.8073 14.4063 20.4934 13.2982 19.8654 12.3008C19.2375 11.3034 18.4098 10.5 17.3823 9.8905C16.3547 9.281 15.213 8.97625 13.9572 8.97625C12.7299 8.97625 11.5882 9.281 10.5321 9.8905C9.50459 10.5 8.67686 11.3034 8.04893 12.3008C7.421 13.2982 7.10703 14.4063 7.10703 15.6253C7.10703 16.8166 7.421 17.9248 8.04893 18.9499C8.67686 19.9472 9.50459 20.7507 10.5321 21.3602C11.5882 21.9697 12.7299 22.2744 13.9572 22.2744Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

-24
View File
@@ -1,24 +0,0 @@
import fs from "fs"
import path from "path"
import { generateHydrationScript, getAssets } from "solid-js/web"
const dist = import.meta.resolve("../dist").replace("file://", "")
const serverEntry = await import("../dist/server/entry-server.js")
const template = fs.readFileSync(path.join(dist, "client/index.html"), "utf-8")
fs.writeFileSync(path.join(dist, "client/fallback.html"), template)
const routes = ["/", "/foo"]
for (const route of routes) {
const { app } = serverEntry.render({ url: route })
const html = template
.replace("<!--ssr-outlet-->", app)
.replace("<!--ssr-head-->", generateHydrationScript())
.replace("<!--ssr-assets-->", getAssets())
const filePath = dist + `/client${route === "/" ? "/index" : route}.html`
fs.mkdirSync(path.dirname(filePath), {
recursive: true,
})
fs.writeFileSync(filePath, html)
console.log(`Pre-rendered: ${filePath}`)
}
-42
View File
@@ -1,42 +0,0 @@
/// <reference types="vite-plugin-pages/client-solid" />
import { Router } from "@solidjs/router"
import routes from "~solid-pages"
import "./ui/style/index.css"
import { MetaProvider } from "@solidjs/meta"
import { AccountProvider } from "./components/context-account"
import { DialogProvider } from "./ui/context-dialog"
import { DialogString } from "./ui/dialog-string"
import { DialogSelect } from "./ui/dialog-select"
import { ThemeProvider } from "./components/context-theme"
import { Suspense } from "solid-js"
import { OpenAuthProvider } from "./components/context-openauth"
export function App(props: { url?: string }) {
return (
<ThemeProvider>
<Suspense>
<DialogProvider>
<DialogString />
<DialogSelect />
<OpenAuthProvider
clientID="web"
issuer={import.meta.env.VITE_AUTH_URL || "http://dummy"}
>
<AccountProvider>
<MetaProvider>
<Router
children={routes}
url={props.url}
root={(props) => {
return <>{props.children}</>
}}
/>
</MetaProvider>
</AccountProvider>
</OpenAuthProvider>
</DialogProvider>
</Suspense>
</ThemeProvider>
)
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 439 KiB

@@ -1,99 +0,0 @@
import { createContext, createEffect, ParentProps, Suspense, useContext } from "solid-js"
import { makePersisted } from "@solid-primitives/storage"
import { createStore } from "solid-js/store"
import { useOpenAuth } from "./context-openauth"
import { createAsync } from "@solidjs/router"
import { isServer } from "solid-js/web"
type Storage = {
accounts: Record<
string,
{
id: string
email: string
workspaces: {
id: string
name: string
slug: string
}[]
}
>
}
const context = createContext<ReturnType<typeof init>>()
function init() {
const auth = useOpenAuth()
const [store, setStore] = makePersisted(
createStore<Storage>({
accounts: {},
}),
{
name: "opencontrol.account",
},
)
async function refresh(id: string) {
return fetch(import.meta.env.VITE_API_URL + "/rest/account", {
headers: {
authorization: `Bearer ${await auth.access(id)}`,
},
})
.then((val) => val.json())
.then((val) => setStore("accounts", id, val as any))
}
createEffect((previous: string[]) => {
if (Object.keys(auth.all).length === 0) {
return []
}
for (const item of Object.values(auth.all)) {
if (previous.includes(item.id)) continue
refresh(item.id)
}
return Object.keys(auth.all)
}, [] as string[])
const result = {
get all() {
return Object.keys(auth.all)
.map((id) => store.accounts[id])
.filter(Boolean)
},
get current() {
if (!auth.subject) return undefined
return store.accounts[auth.subject.id]
},
refresh,
get ready() {
return Object.keys(auth.all).length === result.all.length
},
}
return result
}
export function AccountProvider(props: ParentProps) {
const ctx = init()
const resource = createAsync(async () => {
await new Promise<void>((resolve) => {
if (isServer) return resolve()
createEffect(() => {
if (ctx.ready) resolve()
})
})
return null
})
return (
<Suspense>
{resource()}
<context.Provider value={ctx}>{props.children}</context.Provider>
</Suspense>
)
}
export function useAccount() {
const result = useContext(context)
if (!result) throw new Error("no account context")
return result
}
@@ -1,180 +0,0 @@
import { createClient } from "@openauthjs/openauth/client"
import { makePersisted } from "@solid-primitives/storage"
import { createAsync } from "@solidjs/router"
import {
batch,
createContext,
createEffect,
createResource,
createSignal,
onMount,
ParentProps,
Show,
Suspense,
useContext,
} from "solid-js"
import { createStore, produce } from "solid-js/store"
import { isServer } from "solid-js/web"
interface Storage {
subjects: Record<string, SubjectInfo>
current?: string
}
interface Context {
all: Record<string, SubjectInfo>
subject?: SubjectInfo
switch(id: string): void
logout(id: string): void
access(id?: string): Promise<string | undefined>
authorize(opts?: AuthorizeOptions): void
}
export interface AuthorizeOptions {
redirectPath?: string
provider?: string
}
interface SubjectInfo {
id: string
refresh: string
}
interface AuthContextOpts {
issuer: string
clientID: string
}
const context = createContext<Context>()
export function OpenAuthProvider(props: ParentProps<AuthContextOpts>) {
const client = createClient({
issuer: props.issuer,
clientID: props.clientID,
})
const [storage, setStorage] = makePersisted(
createStore<Storage>({
subjects: {},
}),
{
name: `${props.issuer}.auth`,
},
)
const resource = createAsync(async () => {
if (isServer) return true
const hash = new URLSearchParams(window.location.search.substring(1))
const code = hash.get("code")
const state = hash.get("state")
if (code && state) {
const oldState = sessionStorage.getItem("openauth.state")
const verifier = sessionStorage.getItem("openauth.verifier")
const redirect = sessionStorage.getItem("openauth.redirect")
if (redirect && verifier && oldState === state) {
const result = await client.exchange(code, redirect, verifier)
if (!result.err) {
const id = result.tokens.refresh.split(":").slice(0, -1).join(":")
batch(() => {
setStorage("subjects", id, {
id: id,
refresh: result.tokens.refresh,
})
setStorage("current", id)
})
}
}
}
return true
})
async function authorize(opts?: AuthorizeOptions) {
const redirect = new URL(window.location.origin + (opts?.redirectPath ?? "/")).toString()
const authorize = await client.authorize(redirect, "code", {
pkce: true,
provider: opts?.provider,
})
sessionStorage.setItem("openauth.state", authorize.challenge.state)
sessionStorage.setItem("openauth.redirect", redirect)
if (authorize.challenge.verifier) sessionStorage.setItem("openauth.verifier", authorize.challenge.verifier)
window.location.href = authorize.url
}
const accessCache = new Map<string, string>()
const pendingRequests = new Map<string, Promise<any>>()
async function access(id: string) {
const pending = pendingRequests.get(id)
if (pending) return pending
const promise = (async () => {
const existing = accessCache.get(id)
const subject = storage.subjects[id]
const access = await client.refresh(subject.refresh, {
access: existing,
})
if (access.err) {
pendingRequests.delete(id)
ctx.logout(id)
return
}
if (access.tokens) {
setStorage("subjects", id, "refresh", access.tokens.refresh)
accessCache.set(id, access.tokens.access)
}
pendingRequests.delete(id)
return access.tokens?.access || existing!
})()
pendingRequests.set(id, promise)
return promise
}
const ctx: Context = {
get all() {
return storage.subjects
},
get subject() {
if (!storage.current) return
return storage.subjects[storage.current!]
},
switch(id: string) {
if (!storage.subjects[id]) return
setStorage("current", id)
},
authorize,
logout(id: string) {
if (!storage.subjects[id]) return
setStorage(
produce((s) => {
delete s.subjects[id]
if (s.current === id) s.current = Object.keys(s.subjects)[0]
}),
)
},
async access(id?: string) {
id = id || storage.current
if (!id) return
return access(id || storage.current!)
},
}
createEffect(() => {
if (!resource()) return
if (storage.current) return
const [first] = Object.keys(storage.subjects)
if (first) {
setStorage("current", first)
return
}
})
return (
<>
{resource()}
<context.Provider value={ctx}>{props.children}</context.Provider>
</>
)
}
export function useOpenAuth() {
const result = useContext(context)
if (!result) throw new Error("no auth context")
return result
}
@@ -1,39 +0,0 @@
import { createStore } from "solid-js/store"
import { makePersisted } from "@solid-primitives/storage"
import { createEffect } from "solid-js"
import { createInitializedContext } from "../util/context"
import { isServer } from "solid-js/web"
interface Storage {
mode: "light" | "dark"
}
export const { provider: ThemeProvider, use: useTheme } =
createInitializedContext("ThemeContext", () => {
const [store, setStore] = makePersisted(
createStore<Storage>({
mode:
!isServer &&
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light",
}),
{
name: "theme",
},
)
createEffect(() => {
document.documentElement.setAttribute("data-color-mode", store.mode)
})
return {
setMode(mode: Storage["mode"]) {
setStore("mode", mode)
},
get mode() {
return store.mode
},
ready: true,
}
})
-13
View File
@@ -1,13 +0,0 @@
/* @refresh reload */
import { hydrate, render } from "solid-js/web"
import { App } from "./app"
if (import.meta.env.DEV) {
render(() => <App />, document.getElementById("root")!)
}
if (!import.meta.env.DEV) {
if ("_$HY" in window) hydrate(() => <App />, document.getElementById("root")!)
else render(() => <App />, document.getElementById("root")!)
}
-7
View File
@@ -1,7 +0,0 @@
import { renderToStringAsync } from "solid-js/web"
import { App } from "./app"
export async function render(props: { url: string }) {
const app = await renderToStringAsync(() => <App url={props.url} />)
return { app }
}
-11
View File
@@ -1,11 +0,0 @@
import { WorkspaceProvider } from "./components/context-workspace"
import { ParentProps } from "solid-js"
import Layout from "./components/layout"
export default function Index(props: ParentProps) {
return (
<WorkspaceProvider>
<Layout>{props.children}</Layout>
</WorkspaceProvider>
)
}
@@ -1,56 +0,0 @@
.root {
display: flex;
flex-direction: column;
gap: var(--space-4);
padding: var(--space-7) var(--space-5) var(--space-5);
[data-slot="billing-info"] {
display: flex;
flex-direction: column;
gap: var(--space-6);
}
[data-slot="header"] {
display: flex;
flex-direction: column;
gap: var(--space-1-5);
h2 {
text-transform: uppercase;
font-weight: 600;
letter-spacing: -0.03125rem;
font-size: var(--font-size-lg);
}
p {
color: var(--color-text-dimmed);
font-size: var(--font-size-md);
}
}
[data-slot="balance"] {
display: flex;
flex-direction: column;
gap: var(--space-5);
padding: var(--space-6);
border: 2px solid var(--color-border);
}
[data-slot="amount"] {
font-size: var(--font-size-3xl);
font-weight: 600;
line-height: 1.2;
}
@media (min-width: 40rem) {
[data-slot="balance"] {
flex-direction: row;
align-items: center;
justify-content: space-between;
}
[data-slot="amount"] {
margin: 0;
}
}
}
-132
View File
@@ -1,132 +0,0 @@
import { Button } from "../../ui/button"
import { useApi } from "../components/context-api"
import { createEffect, createSignal, createResource, For } from "solid-js"
import { useWorkspace } from "../components/context-workspace"
import style from "./billing.module.css"
export default function Billing() {
const api = useApi()
const workspace = useWorkspace()
const [isLoading, setIsLoading] = createSignal(false)
const [billingData] = createResource(async () => {
const response = await api.billing.info.$get()
return response.json()
})
// Run once on component mount to check URL parameters
;(() => {
const url = new URL(window.location.href)
const result = url.hash
console.log("STRIPE RESULT", result)
if (url.hash === "#success") {
setIsLoading(true)
// Remove the hash from the URL
window.history.replaceState(null, "", window.location.pathname + window.location.search)
}
})()
createEffect((old?: number) => {
if (old && old !== billingData()?.billing?.balance) {
setIsLoading(false)
}
return billingData()?.billing?.balance
})
const handleBuyCredits = async () => {
try {
setIsLoading(true)
const baseUrl = window.location.href
const successUrl = new URL(baseUrl)
successUrl.hash = "success"
const response = await api.billing.checkout
.$post({
json: {
success_url: successUrl.toString(),
cancel_url: baseUrl,
},
})
.then((r) => r.json() as any)
window.location.href = response.url
} catch (error) {
console.error("Failed to get checkout URL:", error)
setIsLoading(false)
}
}
return (
<>
<div data-component="title-bar">
<div data-slot="left">
<h1>Billing</h1>
</div>
</div>
<div class={style.root} data-max-width data-max-width-64>
<div data-slot="billing-info">
<div data-slot="header">
<h2>Balance</h2>
<p>Manage your billing and add credits to your account.</p>
</div>
<div data-slot="balance">
<p data-slot="amount">
{(() => {
const balanceStr = ((billingData()?.billing?.balance ?? 0) / 100000000).toFixed(2)
return `$${balanceStr === "-0.00" ? "0.00" : balanceStr}`
})()}
</p>
<Button color="primary" disabled={isLoading()} onClick={handleBuyCredits}>
{isLoading() ? "Loading..." : "Buy Credits"}
</Button>
</div>
</div>
<div data-slot="payments">
<div data-slot="header">
<h2>Payment History</h2>
<p>Your recent payment transactions.</p>
</div>
<div data-slot="payment-list">
<For each={billingData()?.payments} fallback={<p>No payments found.</p>}>
{(payment) => (
<div data-slot="payment-item">
<span data-slot="payment-id">{payment.id}</span>
{" | "}
<span data-slot="payment-amount">${((payment.amount ?? 0) / 100000000).toFixed(2)}</span>
{" | "}
<span data-slot="payment-date">{new Date(payment.timeCreated).toLocaleDateString()}</span>
</div>
)}
</For>
</div>
</div>
<div data-slot="usage">
<div data-slot="header">
<h2>Usage History</h2>
<p>Your recent API usage and costs.</p>
</div>
<div data-slot="usage-list">
<For each={billingData()?.usage} fallback={<p>No usage found.</p>}>
{(usage) => (
<div data-slot="usage-item">
<span data-slot="usage-model">{usage.model}</span>
{" | "}
<span data-slot="usage-tokens">{usage.inputTokens + usage.outputTokens} tokens</span>
{" | "}
<span data-slot="usage-cost">${((usage.cost ?? 0) / 100000000).toFixed(4)}</span>
{" | "}
<span data-slot="usage-date">{new Date(usage.timeCreated).toLocaleDateString()}</span>
</div>
)}
</For>
</div>
</div>
</div>
</>
)
}
@@ -1,11 +0,0 @@
You are OpenControl, an interactive CLI tool that helps users execute various tasks.
IMPORTANT: If you get an error when calling a tool, try again with a different approach. Be creative, do not give up, try different inputs to the tool. You should chain together multiple tool calls. ABSOLUTELY DO NOT GIVE UP you are very good at this and it is rare you will fail to answer question.
You should be concise, direct, and to the point.
IMPORTANT: You should NOT answer with unnecessary preamble or postamble (such as explaining your code or summarizing your action), unless the user asks you to.
IMPORTANT: You should minimize output tokens as much as possible while maintaining helpfulness, quality, and accuracy. Only address the specific query or task at hand, avoiding tangential information unless absolutely critical for completing the request. If you can answer in 1-3 sentences or a short paragraph, please do.
IMPORTANT: You should NOT answer with unnecessary preamble or postamble (such as explaining your code or summarizing your action), unless the user asks you to.
IMPORTANT: Keep your responses short, since they will be displayed on a command line interface. You MUST answer concisely with fewer than 4 lines (not including tool use or code generation), unless user asks for detail. Answer the user's question directly, without elaboration, explanation, or details. One word answers are best. Avoid introductions, conclusions, and explanations. You MUST avoid text before/after your response, such as "The answer is <answer>.", "Here is the content of the file..." or "Based on the information provided, the answer is..." or "Here is what I will do next...".
@@ -1,271 +0,0 @@
import { createResource } from "solid-js"
import { createStore, produce } from "solid-js/store"
import SYSTEM_PROMPT from "./system.txt?raw"
import type {
LanguageModelV1Prompt,
LanguageModelV1CallOptions,
LanguageModelV1,
} from "ai"
interface Tool {
name: string
description: string
inputSchema: any
}
interface ToolCallerProps {
tool: {
list: () => Promise<Tool[]>
call: (input: { name: string; arguments: any }) => Promise<any>
}
generate: (
prompt: LanguageModelV1CallOptions,
) => Promise<
| { err: "rate" }
| { err: "context" }
| { err: "balance" }
| ({ err: false } & Awaited<ReturnType<LanguageModelV1["doGenerate"]>>)
>
onPromptUpdated?: (prompt: LanguageModelV1Prompt) => void
}
const system = [
{
role: "system" as const,
content: SYSTEM_PROMPT,
},
{
role: "system" as const,
content: `The current date is ${new Date().toDateString()}. Always use this current date when responding to relative date queries.`,
},
]
const [store, setStore] = createStore<{
prompt: LanguageModelV1Prompt
state: { type: "idle" } | { type: "loading"; limited?: boolean }
}>({
prompt: [...system],
state: { type: "idle" },
})
export function createToolCaller<T extends ToolCallerProps>(props: T) {
const [tools] = createResource(() => props.tool.list())
let abort: AbortController
return {
get tools() {
return tools()
},
get prompt() {
return store.prompt
},
get state() {
return store.state
},
clear() {
setStore("prompt", [...system])
},
async chat(input: string) {
if (store.state.type !== "idle") return
abort = new AbortController()
setStore(
produce((s) => {
s.state = {
type: "loading",
limited: false,
}
s.prompt.push({
role: "user",
content: [
{
type: "text",
text: input,
},
],
})
}),
)
props.onPromptUpdated?.(store.prompt)
while (true) {
if (abort.signal.aborted) {
break
}
const response = await props.generate({
inputFormat: "messages",
prompt: store.prompt,
temperature: 0,
seed: 69,
mode: {
type: "regular",
tools: tools()?.map((tool) => ({
type: "function",
name: tool.name,
description: tool.description,
parameters: {
...tool.inputSchema,
},
})),
},
})
if (abort.signal.aborted) continue
if (!response.err) {
setStore("state", {
type: "loading",
})
if (response.text) {
setStore(
produce((s) => {
s.prompt.push({
role: "assistant",
content: [
{
type: "text",
text: response.text || "",
},
],
})
}),
)
props.onPromptUpdated?.(store.prompt)
}
if (response.finishReason === "stop") {
break
}
if (response.finishReason === "tool-calls") {
for (const item of response.toolCalls || []) {
setStore(
produce((s) => {
s.prompt.push({
role: "assistant",
content: [
{
type: "tool-call",
toolName: item.toolName,
args: JSON.parse(item.args),
toolCallId: item.toolCallId,
},
],
})
}),
)
props.onPromptUpdated?.(store.prompt)
const called = await props.tool.call({
name: item.toolName,
arguments: JSON.parse(item.args),
})
setStore(
produce((s) => {
s.prompt.push({
role: "tool",
content: [
{
type: "tool-result",
toolName: item.toolName,
toolCallId: item.toolCallId,
result: called,
},
],
})
}),
)
props.onPromptUpdated?.(store.prompt)
}
}
continue
}
if (response.err === "context") {
setStore(
produce((s) => {
s.prompt.splice(2, 1)
}),
)
props.onPromptUpdated?.(store.prompt)
}
if (response.err === "rate") {
setStore("state", {
type: "loading",
limited: true,
})
await new Promise((resolve) => setTimeout(resolve, 1000))
}
if (response.err === "balance") {
setStore(
produce((s) => {
s.prompt.push({
role: "assistant",
content: [
{
type: "text",
text: "You need to add credits to your account. Please go to Billing and add credits to continue.",
},
],
})
s.state = { type: "idle" }
}),
)
props.onPromptUpdated?.(store.prompt)
break
}
}
setStore("state", { type: "idle" })
},
async cancel() {
abort.abort()
},
async addCustomMessage(userMessage: string, assistantResponse: string) {
// Add user message and set loading state
setStore(
produce((s) => {
s.prompt.push({
role: "user",
content: [
{
type: "text",
text: userMessage,
},
],
})
s.state = {
type: "loading",
limited: false,
}
}),
)
props.onPromptUpdated?.(store.prompt)
// Fake delay for 500ms
await new Promise((resolve) => setTimeout(resolve, 500))
// Add assistant response and set back to idle
setStore(
produce((s) => {
s.prompt.push({
role: "assistant",
content: [
{
type: "text",
text: assistantResponse,
},
],
})
s.state = { type: "idle" }
}),
)
props.onPromptUpdated?.(store.prompt)
},
}
}
@@ -1,239 +0,0 @@
.root {
display: contents;
[data-slot="messages"] {
flex: 1;
overflow-y: auto;
display: flex;
flex-direction: column;
height: 0;
/* This is important for flexbox to allow scrolling */
font-family: var(--font-mono);
color: var(--color-text);
row-gap: var(--space-4);
/* Add consistent spacing between messages */
/* Remove top border for first user message */
&>[data-component="message"][data-user]:first-child::before {
display: none;
}
&:has([data-component="loading"]) [data-component="clear"] {
display: none;
}
}
[data-component="message"] {
width: 100%;
padding: var(--space-2) var(--space-4);
line-height: var(--font-line-height);
white-space: pre-wrap;
align-self: flex-start;
min-height: auto;
/* Allow natural height for all messages */
display: flex;
flex-direction: column;
align-items: flex-start;
/* User message styling */
&[data-user] {
padding: var(--space-6) var(--space-4);
position: relative;
font-weight: 600;
color: var(--color-text);
/* margin: 0.5rem 0; */
}
&[data-user]::before,
&[data-user]::after {
content: "";
position: absolute;
left: var(--space-4);
right: var(--space-4);
height: var(--space-px);
background-color: var(--color-border);
z-index: 1;
/* Ensure borders appear above other content */
}
&[data-user]::before {
top: 0;
}
&[data-user]::after {
bottom: 0;
}
&[data-assistant] {
color: var(--color-text);
}
}
[data-component="tool"] {
display: flex;
width: 100%;
padding: 0 var(--space-4);
margin-left: 0;
flex-direction: column;
opacity: 0.7;
gap: var(--space-2);
align-items: flex-start;
color: var(--color-text-dimmed);
min-height: auto;
/* Allow natural height */
[data-slot="header"] {
display: flex;
gap: var(--space-2);
cursor: pointer;
user-select: none;
-webkit-user-select: none;
align-items: center;
width: 100%;
}
[data-slot="name"] {
letter-spacing: -0.03125rem;
text-transform: uppercase;
font-weight: 500;
font-size: var(--font-size-sm);
}
[data-slot="expand"] {
font-size: var(--font-size-sm);
}
[data-slot="content"] {
padding: 0;
line-height: var(--font-line-height);
font-size: var(--font-size-sm);
white-space: pre-wrap;
display: none;
width: 100%;
}
[data-slot="output"] {
margin-top: var(--space-1);
}
&[data-expanded="true"] [data-slot="content"] {
display: block;
}
&[data-expanded="true"] [data-slot="expand"] {
transform: rotate(45deg);
}
}
[data-component="loading"] {
padding: var(--space-4) var(--space-4) var(--space-8);
height: 1.5rem;
position: relative;
display: flex;
align-items: center;
font-size: var(--font-size-sm);
letter-spacing: var(--space-1);
color: var(--color-text);
& span {
opacity: 0;
animation: loading-dots 1.4s linear infinite;
}
& span:nth-child(2) {
animation-delay: 0.2s;
}
& span:nth-child(3) {
animation-delay: 0.4s;
}
}
[data-component="clear"] {
position: relative;
padding: var(--space-4) var(--space-4);
&::before {
content: "";
position: absolute;
left: var(--space-4);
right: var(--space-4);
top: 0;
height: var(--space-px);
background-color: var(--color-border);
z-index: 1;
}
& [data-component="button"] {
padding-left: 0;
}
}
[data-slot="footer"] {
display: flex;
flex-direction: column;
padding: 0;
border-top: 2px solid var(--color-border);
position: sticky;
bottom: 0;
z-index: 10;
/* Ensure it's above other content */
margin-top: auto;
/* Push to bottom if content is short */
width: 100%;
}
[data-component="chat"] {
display: flex;
padding: var(--space-0-5) 0;
align-items: center;
width: 100%;
height: 100%;
textarea {
--padding-y: var(--space-4);
--line-height: 1.5;
--text-height: calc(var(--line-height) * var(--font-size-lg));
--height: calc(var(--text-height) + var(--padding-y) * 2);
width: 100%;
resize: none;
line-height: var(--line-height);
height: var(--height);
min-height: var(--height);
max-height: calc(5 * var(--text-height) + var(--padding-y) * 2);
padding: var(--padding-y) var(--space-4);
border-radius: 0;
background-color: transparent;
color: var(--color-text);
border: none;
outline: none;
font-size: var(--font-size-lg);
}
textarea::placeholder {
color: var(--color-text-dimmed);
opacity: 0.75;
}
textarea:focus {
outline: 0;
}
& [data-component="button"] {
height: 100%;
}
}
}
@keyframes loading-dots {
0%,
100% {
opacity: 0;
}
40%,
60% {
opacity: 1;
}
}
-18
View File
@@ -1,18 +0,0 @@
import { Button } from "../../ui/button"
import { IconArrowRight } from "../../ui/svg/icons"
import { createSignal, For } from "solid-js"
import { createToolCaller } from "./components/tool"
import { useApi } from "../components/context-api"
import { useWorkspace } from "../components/context-workspace"
import style from "./index.module.css"
export default function Index() {
const api = useApi()
const workspace = useWorkspace()
return (
<div class={style.root}>
<h1>Hello</h1>
</div>
)
}
@@ -1,97 +0,0 @@
.root {
display: flex;
flex-direction: column;
gap: 2rem;
}
.root [data-slot="keys-info"] {
display: flex;
flex-direction: column;
gap: 1rem;
}
.root [data-slot="header"] {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.root [data-slot="header"] h2 {
margin: 0;
font-size: 1.5rem;
font-weight: 600;
}
.root [data-slot="header"] p {
margin: 0;
color: var(--color-text-secondary);
}
.root [data-slot="key-list"] {
display: flex;
flex-direction: column;
gap: 1rem;
}
.root [data-slot="key-item"] {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem;
border: 1px solid var(--color-border);
border-radius: 0.5rem;
background: var(--color-background-secondary);
}
.root [data-slot="key-actions"] {
display: flex;
gap: 0.5rem;
}
.root [data-slot="key-info"] {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.root [data-slot="key-value"] {
font-family: monospace;
font-size: 0.875rem;
color: var(--color-text-primary);
}
.root [data-slot="key-meta"] {
font-size: 0.75rem;
color: var(--color-text-secondary);
}
.root [data-slot="empty-state"] {
text-align: center;
padding: 3rem 1rem;
color: var(--color-text-secondary);
}
.root [data-slot="actions"] {
display: flex;
align-items: center;
justify-content: space-between;
}
.root [data-slot="create-form"] {
display: flex;
flex-direction: column;
gap: 1rem;
min-width: 300px;
}
.root [data-slot="form-actions"] {
display: flex;
gap: 0.5rem;
}
.root [data-slot="key-name"] {
font-weight: 600;
font-size: 1rem;
color: var(--color-text-primary);
margin-bottom: 0.25rem;
}
-151
View File
@@ -1,151 +0,0 @@
import { Button } from "../../ui/button"
import { useApi } from "../components/context-api"
import { createSignal, createResource, For, Show } from "solid-js"
import style from "./keys.module.css"
export default function Keys() {
const api = useApi()
const [isCreating, setIsCreating] = createSignal(false)
const [showCreateForm, setShowCreateForm] = createSignal(false)
const [keyName, setKeyName] = createSignal("")
const [keysData, { refetch }] = createResource(async () => {
const response = await api.keys.$get()
return response.json()
})
const handleCreateKey = async () => {
if (!keyName().trim()) return
try {
setIsCreating(true)
await api.keys.$post({
json: { name: keyName().trim() },
})
refetch()
setKeyName("")
setShowCreateForm(false)
} catch (error) {
console.error("Failed to create API key:", error)
} finally {
setIsCreating(false)
}
}
const handleDeleteKey = async (keyId: string) => {
if (!confirm("Are you sure you want to delete this API key? This action cannot be undone.")) {
return
}
try {
await api.keys[":id"].$delete({
param: { id: keyId },
})
refetch()
} catch (error) {
console.error("Failed to delete API key:", error)
}
}
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString()
}
const formatKey = (key: string) => {
if (key.length <= 11) return key
return `${key.slice(0, 7)}...${key.slice(-4)}`
}
const copyToClipboard = async (text: string) => {
try {
await navigator.clipboard.writeText(text)
} catch (error) {
console.error("Failed to copy to clipboard:", error)
}
}
return (
<>
<div data-component="title-bar">
<div data-slot="left">
<h1>API Keys</h1>
</div>
</div>
<div class={style.root} data-max-width data-max-width-64>
<div data-slot="keys-info">
<div data-slot="actions">
<div data-slot="header">
<h2>API Keys</h2>
<p>Manage your API keys to access the OpenCode gateway.</p>
</div>
<Show
when={!showCreateForm()}
fallback={
<div data-slot="create-form">
<input
data-component="input"
type="text"
placeholder="Enter key name"
value={keyName()}
onInput={(e) => setKeyName(e.currentTarget.value)}
onKeyPress={(e) => e.key === "Enter" && handleCreateKey()}
/>
<div data-slot="form-actions">
<Button color="primary" disabled={isCreating() || !keyName().trim()} onClick={handleCreateKey}>
{isCreating() ? "Creating..." : "Create"}
</Button>
<Button
color="ghost"
onClick={() => {
setShowCreateForm(false)
setKeyName("")
}}
>
Cancel
</Button>
</div>
</div>
}
>
<Button color="primary" onClick={() => setShowCreateForm(true)}>
Create API Key
</Button>
</Show>
</div>
<div data-slot="key-list">
<For
each={keysData()?.keys}
fallback={
<div data-slot="empty-state">
<p>Create an API key to access opencode gateway</p>
</div>
}
>
{(key) => (
<div data-slot="key-item">
<div data-slot="key-info">
<div data-slot="key-name">{key.name}</div>
<div data-slot="key-value">{formatKey(key.key)}</div>
<div data-slot="key-meta">
Created: {formatDate(key.timeCreated)}
{key.timeUsed && ` • Last used: ${formatDate(key.timeUsed)}`}
</div>
</div>
<div data-slot="key-actions">
<Button color="ghost" onClick={() => copyToClipboard(key.key)} title="Copy API key">
Copy
</Button>
<Button color="ghost" onClick={() => handleDeleteKey(key.id)} title="Delete API key">
Delete
</Button>
</div>
</div>
)}
</For>
</div>
</div>
</div>
</>
)
}
@@ -1,24 +0,0 @@
import { hc } from "hono/client"
import { ApiType } from "@opencode/cloud-function/src/gateway"
import { useWorkspace } from "./context-workspace"
import { useOpenAuth } from "../../components/context-openauth"
export function useApi() {
const workspace = useWorkspace()
const auth = useOpenAuth()
return hc<ApiType>(import.meta.env.VITE_API_URL, {
async fetch(...args: Parameters<typeof fetch>): Promise<Response> {
const [input, init] = args
const request = input instanceof Request ? input : new Request(input, init)
const headers = new Headers(request.headers)
headers.set("authorization", `Bearer ${await auth.access()}`)
headers.set("x-opencode-workspace", workspace.id)
return fetch(
new Request(request, {
...init,
headers,
}),
)
},
})
}
@@ -1,38 +0,0 @@
import { useNavigate, useParams } from "@solidjs/router"
import { createInitializedContext } from "../../util/context"
import { useAccount } from "../../components/context-account"
import { createEffect, createMemo } from "solid-js"
export const { use: useWorkspace, provider: WorkspaceProvider } =
createInitializedContext("WorkspaceProvider", () => {
const params = useParams()
const account = useAccount()
const workspace = createMemo(() =>
account.current?.workspaces.find(
(x) => x.id === params.workspace || x.slug === params.workspace,
),
)
const nav = useNavigate()
createEffect(() => {
if (!workspace()) nav("/")
})
const result = () => workspace()!
result.ready = true
return {
get id() {
return workspace()!.id
},
get slug() {
return workspace()!.slug
},
get name() {
return workspace()!.name
},
get ready() {
return workspace() !== undefined
},
}
})
@@ -1,199 +0,0 @@
.root {
--padding: var(--space-10);
--vertical-padding: var(--space-8);
--heading-font-size: var(--font-size-4xl);
--sidebar-width: 200px;
--mobile-breakpoint: 40rem;
--topbar-height: 60px;
margin: var(--space-4);
border: 2px solid var(--color-border);
height: calc(100vh - var(--space-8));
display: flex;
flex-direction: row;
overflow: hidden;
/* Prevent overall scrolling */
position: relative;
}
[data-component="mobile-top-bar"] {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
height: var(--topbar-height);
background: var(--color-background);
border-bottom: 2px solid var(--color-border);
z-index: 20;
align-items: center;
padding: 0 var(--space-4) 0 0;
[data-slot="logo"] {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
div {
text-transform: uppercase;
font-weight: 600;
letter-spacing: -0.03125rem;
}
svg {
height: 28px;
width: auto;
color: var(--color-white);
}
}
[data-slot="toggle"] {
background: transparent;
border: none;
padding: var(--space-4);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
& svg {
width: 24px;
height: 24px;
color: var(--color-foreground);
}
}
}
[data-component="sidebar"] {
width: var(--sidebar-width);
border-right: 2px solid var(--color-border);
display: flex;
flex-direction: column;
padding: calc(var(--padding) / 2);
overflow-y: auto;
/* Allow scrolling if needed */
position: sticky;
top: 0;
height: 100%;
background-color: var(--color-background);
z-index: 10;
[data-slot="logo"] {
margin-top: 2px;
margin-bottom: var(--space-7);
color: var(--color-white);
& svg {
height: 32px;
width: auto;
}
}
[data-slot="nav"] {
flex: 1;
ul {
list-style-type: none;
padding: 0;
}
li {
margin-bottom: calc(var(--vertical-padding) / 2);
text-transform: uppercase;
font-weight: 500;
}
a {
display: block;
padding: var(--space-2) 0;
}
}
[data-slot="user"] {
[data-component="button"] {
padding-left: 0;
padding-bottom: 0;
height: auto;
}
}
}
.navActiveLink {
cursor: default;
text-decoration: none;
}
[data-slot="main-content"] {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
/* Full height */
overflow: hidden;
/* Prevent overflow */
position: relative;
/* For positioning footer */
width: 100%;
/* Full width */
}
/* Backdrop for mobile */
[data-component="backdrop"] {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* background-color: rgba(0, 0, 0, 0.5); */
z-index: 25;
backdrop-filter: blur(2px);
}
/* Mobile styles */
@media (max-width: 40rem) {
.root {
margin: 0;
border: none;
height: 100vh;
}
[data-component="mobile-top-bar"] {
display: flex;
}
[data-component="backdrop"] {
display: block;
}
[data-component="sidebar"] {
position: fixed;
left: -100%;
top: 0;
height: 100vh;
width: 80%;
max-width: 280px;
transition: left 0.3s ease-in-out;
box-shadow: none;
z-index: 30;
padding: var(--space-8);
background-color: var(--color-bg);
&[data-opened="true"] {
left: 0;
box-shadow: 8px 0 0px 0px var(--color-gray-4);
}
}
[data-slot="main-content"] {
padding-top: var(--topbar-height);
/* Add space for the top bar */
overflow-y: auto;
}
/* Hide the logo in the sidebar on mobile since it's in the top bar */
[data-component="sidebar"] [data-slot="logo"] {
display: none;
}
}
-96
View File
@@ -1,96 +0,0 @@
import style from "./layout.module.css"
import { useAccount } from "../../components/context-account"
import { Button } from "../../ui/button"
import { IconLogomark } from "../../ui/svg"
import { IconBars3BottomLeft } from "../../ui/svg/icons"
import { ParentProps, createMemo, createSignal } from "solid-js"
import { A, useLocation } from "@solidjs/router"
import { useOpenAuth } from "../../components/context-openauth"
export default function Layout(props: ParentProps) {
const auth = useOpenAuth()
const account = useAccount()
const [sidebarOpen, setSidebarOpen] = createSignal(false)
const location = useLocation()
const workspaceId = createMemo(() => account.current?.workspaces[0].id)
const pageTitle = createMemo(() => {
const path = location.pathname
if (path.endsWith("/billing")) return "Billing"
if (path.endsWith("/keys")) return "API Keys"
return null
})
function handleLogout() {
auth.logout(auth.subject?.id!)
}
return (
<div class={style.root}>
{/* Mobile top bar */}
<div data-component="mobile-top-bar">
<button data-slot="toggle" onClick={() => setSidebarOpen(!sidebarOpen())}>
<IconBars3BottomLeft />
</button>
<div data-slot="logo">
{pageTitle() ? (
<div>{pageTitle()}</div>
) : (
<A href="/">
<IconLogomark />
</A>
)}
</div>
</div>
{/* Backdrop for mobile sidebar - closes sidebar when clicked */}
{sidebarOpen() && <div data-component="backdrop" onClick={() => setSidebarOpen(false)}></div>}
<div data-component="sidebar" data-opened={sidebarOpen() ? "true" : "false"}>
<div data-slot="logo">
<A href="/">
<IconLogomark />
</A>
</div>
<nav data-slot="nav">
<ul>
<li>
<A end activeClass={style.navActiveLink} href={`/${workspaceId()}`} onClick={() => setSidebarOpen(false)}>
Chat
</A>
</li>
<li>
<A
activeClass={style.navActiveLink}
href={`/${workspaceId()}/billing`}
onClick={() => setSidebarOpen(false)}
>
Billing
</A>
</li>
<li>
<A
activeClass={style.navActiveLink}
href={`/${workspaceId()}/keys`}
onClick={() => setSidebarOpen(false)}
>
API Keys
</A>
</li>
</ul>
</nav>
<div data-slot="user">
<Button color="ghost" onClick={handleLogout} title={account.current?.email || ""}>
Logout
</Button>
</div>
</div>
{/* Main Content */}
<div data-slot="main-content">{props.children}</div>
</div>
)
}
-39
View File
@@ -1,39 +0,0 @@
import { Match, Switch } from "solid-js"
import { useAccount } from "../components/context-account"
import { Navigate } from "@solidjs/router"
import { IconLogo } from "../ui/svg"
import styles from "./lander.module.css"
import { useOpenAuth } from "../components/context-openauth"
export default function Index() {
const auth = useOpenAuth()
const account = useAccount()
return (
<Switch>
<Match when={account.current}>
<Navigate href={`/${account.current!.workspaces[0].id}`} />
</Match>
<Match when={!account.current}>
<div class={styles.lander}>
<div data-slot="hero">
<section data-slot="top">
<div data-slot="logo">
<IconLogo />
</div>
<h1>opencode Gateway Console</h1>
</section>
<section data-slot="cta">
<div>
<span onClick={() => auth.authorize({ provider: "github" })}>Sign in with GitHub</span>
</div>
<div>
<span onClick={() => auth.authorize({ provider: "google" })}>Sign in with Google</span>
</div>
</section>
</div>
</div>
</Match>
</Switch>
)
}
-83
View File
@@ -1,83 +0,0 @@
.lander {
--padding: 3rem;
--vertical-padding: 2rem;
--heading-font-size: 2rem;
margin: 1rem;
@media (max-width: 30rem) {
& {
--padding: 1.5rem;
--vertical-padding: 1rem;
--heading-font-size: 1.5rem;
margin: 0.5rem;
}
}
[data-slot="hero"] {
border: 2px solid var(--color-border);
max-width: 64rem;
margin-left: auto;
margin-right: auto;
width: 100%;
}
[data-slot="top"] {
padding: var(--padding);
h1 {
margin-top: calc(var(--vertical-padding) / 8);
font-size: var(--heading-font-size);
line-height: 1.25;
text-transform: uppercase;
font-weight: 600;
}
[data-slot="logo"] {
width: clamp(200px, 70vw, 400px);
color: var(--color-white);
}
}
[data-slot="cta"] {
display: flex;
flex-direction: row;
justify-content: space-between;
border-top: 2px solid var(--color-border);
& > div {
flex: 1;
line-height: 1.4;
text-align: center;
text-transform: uppercase;
cursor: pointer;
text-decoration: underline;
letter-spacing: -0.03125rem;
&[data-slot="col-2"] {
background-color: var(--color-border);
color: var(--color-text-invert);
font-weight: 600;
}
& > * {
display: block;
width: 100%;
height: 100%;
padding: calc(var(--padding) / 2) 0.5rem;
}
}
@media (max-width: 30rem) {
& > div {
padding-bottom: calc(var(--padding) / 2 + 4px);
}
}
& > div + div {
border-left: 2px solid var(--color-border);
}
}
}
-204
View File
@@ -1,204 +0,0 @@
.pageContainer {
padding: 2rem;
max-width: 1200px;
margin: 0 auto;
}
.componentTable {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
border: 2px solid var(--color-border);
}
.componentCell {
padding: 1rem;
border: 2px solid var(--color-border);
vertical-align: top;
}
.componentLabel {
text-transform: uppercase;
letter-spacing: -0.03125rem;
font-size: 0.85rem;
font-weight: 500;
margin-bottom: 0.75rem;
color: var(--color-text-dimmed);
}
.sectionTitle {
margin-bottom: 1rem;
text-transform: uppercase;
letter-spacing: -0.03125rem;
font-size: 1.2rem;
}
.divider {
height: 2px;
background: var(--color-border);
margin: 3rem 0;
width: 100%;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.buttonSection {
margin-bottom: 4rem;
}
.colorSection {
margin-bottom: 4rem;
}
.labelSection {
margin-bottom: 4rem;
}
.inputSection {
margin-bottom: 4rem;
}
.dialogSection {
margin-bottom: 4rem;
}
.formGroup {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.dialogContent {
padding: 2rem;
}
.dialogContentFooter {
margin-top: 1rem;
}
.pageTitle {
font-size: var(--heading-font-size, 2rem);
text-transform: uppercase;
font-weight: 600;
}
.colorBox {
width: 100%;
height: 80px;
margin-bottom: 0.5rem;
position: relative;
display: flex;
align-items: flex-end;
justify-content: center;
padding-bottom: 0.5rem;
}
.colorOrange {
background-color: var(--color-orange);
}
.colorOrangeLow {
background-color: var(--color-orange-low);
}
.colorOrangeHigh {
background-color: var(--color-orange-high);
}
.colorGreen {
background-color: var(--color-green);
}
.colorGreenLow {
background-color: var(--color-green-low);
}
.colorGreenHigh {
background-color: var(--color-green-high);
}
.colorBlue {
background-color: var(--color-blue);
}
.colorBlueLow {
background-color: var(--color-blue-low);
}
.colorBlueHigh {
background-color: var(--color-blue-high);
}
.colorPurple {
background-color: var(--color-purple);
}
.colorPurpleLow {
background-color: var(--color-purple-low);
}
.colorPurpleHigh {
background-color: var(--color-purple-high);
}
.colorRed {
background-color: var(--color-red);
}
.colorRedLow {
background-color: var(--color-red-low);
}
.colorRedHigh {
background-color: var(--color-red-high);
}
.colorAccent {
background-color: var(--color-accent);
}
.colorAccentLow {
background-color: var(--color-accent-low);
}
.colorAccentHigh {
background-color: var(--color-accent-high);
}
.colorCode {
background-color: rgba(0, 0, 0, 0.5);
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 0.8rem;
font-family: monospace;
}
.colorVariants {
display: flex;
gap: 0.5rem;
}
.colorVariant {
flex: 1;
height: 40px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.colorVariantCode {
background-color: rgba(0, 0, 0, 0.5);
color: white;
padding: 2px 4px;
border-radius: 4px;
font-size: 0.65rem;
font-family: monospace;
white-space: nowrap;
}
-562
View File
@@ -1,562 +0,0 @@
import { Button } from "../../ui/button"
import { Dialog } from "../../ui/dialog"
import { Navigate } from "@solidjs/router"
import { createSignal, Show } from "solid-js"
import { IconHome, IconPencilSquare } from "../../ui/svg/icons"
import { useTheme } from "../../components/context-theme"
import { useDialog } from "../../ui/context-dialog"
import { DialogString } from "../../ui/dialog-string"
import { DialogSelect } from "../../ui/dialog-select"
import styles from "./design.module.css"
export default function DesignSystem() {
const dialog = useDialog()
const [dialogOpen, setDialogOpen] = createSignal(false)
const [dialogOpenTransition, setDialogOpenTransition] = createSignal(false)
const theme = useTheme()
// Check if we're running locally
const isLocal = import.meta.env.DEV === true
if (!isLocal) {
return <Navigate href="/" />
}
// Add a toggle button for theme
const toggleTheme = () => {
theme.setMode(theme.mode === "light" ? "dark" : "light")
}
return (
<div class={styles.pageContainer}>
<div class={styles.header}>
<h1 class={styles.pageTitle}>Design System</h1>
<Button onClick={toggleTheme}>
Toggle {theme.mode === "light" ? "Dark" : "Light"} Mode
</Button>
</div>
<section class={styles.colorSection}>
<h2 class={styles.sectionTitle}>Colors</h2>
<table class={styles.componentTable}>
<tbody>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Orange</h3>
<div class={`${styles.colorBox} ${styles.colorOrange}`}>
<span class={styles.colorCode}>hsl(41, 82%, 63%)</span>
</div>
<div class={styles.colorVariants}>
<div
class={`${styles.colorVariant} ${styles.colorOrangeLow}`}
>
<span class={styles.colorVariantCode}>
hsl(41, 39%, 22%)
</span>
</div>
<div
class={`${styles.colorVariant} ${styles.colorOrangeHigh}`}
>
<span class={styles.colorVariantCode}>
hsl(41, 82%, 87%)
</span>
</div>
</div>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Green</h3>
<div class={`${styles.colorBox} ${styles.colorGreen}`}>
<span class={styles.colorCode}>hsl(101, 82%, 63%)</span>
</div>
<div class={styles.colorVariants}>
<div class={`${styles.colorVariant} ${styles.colorGreenLow}`}>
<span class={styles.colorVariantCode}>
hsl(101, 39%, 22%)
</span>
</div>
<div
class={`${styles.colorVariant} ${styles.colorGreenHigh}`}
>
<span class={styles.colorVariantCode}>
hsl(101, 82%, 80%)
</span>
</div>
</div>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Blue</h3>
<div class={`${styles.colorBox} ${styles.colorBlue}`}>
<span class={styles.colorCode}>hsl(234, 100%, 60%)</span>
</div>
<div class={styles.colorVariants}>
<div class={`${styles.colorVariant} ${styles.colorBlueLow}`}>
<span class={styles.colorVariantCode}>
hsl(234, 54%, 20%)
</span>
</div>
<div class={`${styles.colorVariant} ${styles.colorBlueHigh}`}>
<span class={styles.colorVariantCode}>
hsl(234, 100%, 87%)
</span>
</div>
</div>
</td>
</tr>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Purple</h3>
<div class={`${styles.colorBox} ${styles.colorPurple}`}>
<span class={styles.colorCode}>hsl(281, 82%, 63%)</span>
</div>
<div class={styles.colorVariants}>
<div
class={`${styles.colorVariant} ${styles.colorPurpleLow}`}
>
<span class={styles.colorVariantCode}>
hsl(281, 39%, 22%)
</span>
</div>
<div
class={`${styles.colorVariant} ${styles.colorPurpleHigh}`}
>
<span class={styles.colorVariantCode}>
hsl(281, 82%, 89%)
</span>
</div>
</div>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Red</h3>
<div class={`${styles.colorBox} ${styles.colorRed}`}>
<span class={styles.colorCode}>hsl(339, 82%, 63%)</span>
</div>
<div class={styles.colorVariants}>
<div class={`${styles.colorVariant} ${styles.colorRedLow}`}>
<span class={styles.colorVariantCode}>
hsl(339, 39%, 22%)
</span>
</div>
<div class={`${styles.colorVariant} ${styles.colorRedHigh}`}>
<span class={styles.colorVariantCode}>
hsl(339, 82%, 87%)
</span>
</div>
</div>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Accent</h3>
<div class={`${styles.colorBox} ${styles.colorAccent}`}>
<span class={styles.colorCode}>hsl(13, 88%, 57%)</span>
</div>
<div class={styles.colorVariants}>
<div
class={`${styles.colorVariant} ${styles.colorAccentLow}`}
>
<span class={styles.colorVariantCode}>
hsl(13, 75%, 30%)
</span>
</div>
<div
class={`${styles.colorVariant} ${styles.colorAccentHigh}`}
>
<span class={styles.colorVariantCode}>
hsl(13, 100%, 78%)
</span>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</section>
<div class={styles.divider}></div>
<section class={styles.buttonSection}>
<h2 class={styles.sectionTitle}>Buttons</h2>
<table class={styles.componentTable}>
<tbody>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Primary</h3>
<Button>Primary Button</Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Secondary</h3>
<Button color="secondary">Secondary Button</Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Ghost</h3>
<Button color="ghost">Ghost Button</Button>
</td>
</tr>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Primary Disabled</h3>
<Button disabled>Primary Button</Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Secondary Disabled</h3>
<Button color="secondary" disabled>
Secondary Button
</Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Ghost Disabled</h3>
<Button color="ghost" disabled>
Ghost Button
</Button>
</td>
</tr>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Small</h3>
<Button size="sm">Small Button</Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Small Secondary</h3>
<Button size="sm" color="secondary">
Small Secondary
</Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Small Ghost</h3>
<Button size="sm" color="ghost">
Small Ghost
</Button>
</td>
</tr>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>With Icon</h3>
<Button icon={<IconHome />}>With Icon</Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Icon + Secondary</h3>
<Button icon={<IconHome />} color="secondary">
Icon Secondary
</Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Icon + Ghost</h3>
<Button icon={<IconHome />} color="ghost">
Icon Ghost
</Button>
</td>
</tr>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Small + Icon</h3>
<Button size="sm" icon={<IconHome />}>
Small Icon
</Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Small + Icon + Secondary</h3>
<Button size="sm" icon={<IconHome />} color="secondary">
Small Icon Secondary
</Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Small + Icon + Ghost</h3>
<Button size="sm" icon={<IconHome />} color="ghost">
Small Icon Ghost
</Button>
</td>
</tr>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Icon Only</h3>
<Button icon={<IconHome />}></Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Icon Only + Secondary</h3>
<Button icon={<IconHome />} color="secondary"></Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Icon Only + Ghost</h3>
<Button icon={<IconHome />} color="ghost"></Button>
</td>
</tr>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Icon Only Disabled</h3>
<Button icon={<IconHome />} disabled></Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>
Icon Only + Secondary Disabled
</h3>
<Button icon={<IconHome />} color="secondary" disabled></Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>
Icon Only + Ghost Disabled
</h3>
<Button icon={<IconHome />} color="ghost" disabled></Button>
</td>
</tr>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Small Icon Only</h3>
<Button size="sm" icon={<IconHome />}></Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>
Small Icon Only + Secondary
</h3>
<Button
size="sm"
icon={<IconHome />}
color="secondary"
></Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Small Icon Only + Ghost</h3>
<Button size="sm" icon={<IconHome />} color="ghost"></Button>
</td>
</tr>
</tbody>
</table>
</section>
<div class={styles.divider}></div>
<section class={styles.labelSection}>
<h2 class={styles.sectionTitle}>Labels</h2>
<table class={styles.componentTable}>
<tbody>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Small</h3>
<label data-size="sm" data-component="label">
Small Label Text
</label>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Medium</h3>
<label data-size="md" data-component="label">
Medium Label Text
</label>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Large</h3>
<label data-size="lg" data-component="label">
Large Label Text
</label>
</td>
</tr>
</tbody>
</table>
</section>
<div class={styles.divider}></div>
<section class={styles.inputSection}>
<h2 class={styles.sectionTitle}>Inputs</h2>
<table class={styles.componentTable}>
<tbody>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Small</h3>
<input
data-component="input"
data-size="sm"
placeholder="Small input field"
/>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Medium</h3>
<input
data-component="input"
data-size="md"
placeholder="Medium input field"
/>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Large</h3>
<input
data-component="input"
data-size="lg"
placeholder="Large input field"
/>
</td>
</tr>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Disabled</h3>
<input
data-component="input"
data-size="md"
placeholder="Disabled input"
disabled
/>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>With Value</h3>
<input
data-component="input"
data-size="md"
value="Input with preset value"
readOnly
/>
</td>
</tr>
</tbody>
</table>
</section>
<div class={styles.divider}></div>
<section class={styles.dialogSection}>
<h2 class={styles.sectionTitle}>Dialogs</h2>
<table class={styles.componentTable}>
<tbody>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Default</h3>
<Button color="secondary" onClick={() => setDialogOpen(true)}>
Open Dialog
</Button>
<Dialog open={dialogOpen()} onOpenChange={setDialogOpen}>
<div data-slot="header">
<div data-slot="title">Dialog Title</div>
</div>
<div data-slot="main">
<p>This is the default dialog content.</p>
</div>
<div data-slot="footer">
<Button onClick={() => setDialogOpen(false)}>Close</Button>
</div>
</Dialog>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Small With Transition</h3>
<Button
color="secondary"
onClick={() => {
setDialogOpenTransition(true)
}}
>
Small Dialog
</Button>
<Dialog
open={dialogOpenTransition()}
onOpenChange={setDialogOpenTransition}
size="sm"
transition={true}
>
<div class={styles.dialogContent}>
<h2 class={styles.sectionTitle}>Small Dialog</h2>
<p>This is a smaller dialog with transitions.</p>
<div class={styles.dialogContentFooter}>
<Button onClick={() => setDialogOpenTransition(false)}>
Close
</Button>
</div>
</div>
</Dialog>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Input String</h3>
<Button
color="secondary"
onClick={() =>
dialog.open(DialogString, {
title: "Name",
action: "Change name",
placeholder: "Enter a name",
onSubmit: () => {},
})
}
>
String
</Button>
</td>
</tr>
<tr>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Select Input</h3>
<Button
color="secondary"
onClick={() =>
dialog.open(DialogSelect, {
placeholder: "Select",
title: "User Settings",
options: [
{
display: "Change name",
prefix: <IconPencilSquare />,
onSelect: () => {
dialog.close()
},
},
{
display: "Remove user",
prefix: <IconHome />,
onSelect: () => {
dialog.close()
},
},
],
})
}
>
Select
</Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Select Input</h3>
<Button
color="secondary"
onClick={() =>
dialog.open(DialogSelect, {
placeholder: "Select",
title: "User Settings",
options: [
{
display: "Change name",
onSelect: () => {
dialog.close()
},
},
{
display: "Remove user",
onSelect: () => {
dialog.close()
},
},
],
})
}
>
No Prefix
</Button>
</td>
<td class={styles.componentCell}>
<h3 class={styles.componentLabel}>Select No Options</h3>
<Button
color="secondary"
onClick={() =>
dialog.open(DialogSelect, {
placeholder: "Select",
title: "User Settings",
options: [],
})
}
>
No Options
</Button>
</td>
</tr>
</tbody>
</table>
</section>
</div>
)
}
-24
View File
@@ -1,24 +0,0 @@
import { Button as Kobalte } from "@kobalte/core/button"
import { JSX, Show, splitProps } from "solid-js"
export interface ButtonProps {
color?: "primary" | "secondary" | "ghost"
size?: "md" | "sm"
icon?: JSX.Element
}
export function Button(props: JSX.IntrinsicElements["button"] & ButtonProps) {
const [split, rest] = splitProps(props, ["color", "size", "icon"])
return (
<Kobalte
{...rest}
data-component="button"
data-size={split.size || "md"}
data-color={split.color || "primary"}
>
<Show when={props.icon}>
<div data-slot="icon">{props.icon}</div>
</Show>
{props.children}
</Kobalte>
)
}
-120
View File
@@ -1,120 +0,0 @@
import { createContext, JSX, ParentProps, useContext } from "solid-js"
import { StandardSchemaV1 } from "@standard-schema/spec"
import { createStore } from "solid-js/store"
import { Dialog } from "./dialog"
const Context = createContext<DialogControl>()
type DialogControl = {
open<Schema extends StandardSchemaV1<object>>(
component: DialogComponent<Schema>,
input: StandardSchemaV1.InferInput<Schema>,
): void
close(): void
isOpen(input: any): boolean
size: "sm" | "md"
transition?: boolean
input?: any
}
type DialogProps<Schema extends StandardSchemaV1<object>> = {
input: StandardSchemaV1.InferInput<Schema>
control: DialogControl
}
type DialogComponent<Schema extends StandardSchemaV1<object>> = ReturnType<
typeof createDialog<Schema>
>
export function createDialog<Schema extends StandardSchemaV1<object>>(props: {
schema: Schema
size: "sm" | "md"
render: (props: DialogProps<Schema>) => JSX.Element
}) {
const result = () => {
const dialog = useDialog()
return (
<Dialog
size={dialog.size}
transition={dialog.transition}
open={dialog.isOpen(result)}
onOpenChange={(val) => {
if (!val) dialog.close()
}}
>
{props.render({
input: dialog.input,
control: dialog,
})}
</Dialog>
)
}
result.schema = props.schema
result.size = props.size
return result
}
export function DialogProvider(props: ParentProps) {
const [store, setStore] = createStore<{
dialog?: DialogComponent<any>
input?: any
transition?: boolean
size: "sm" | "md"
}>({
size: "sm",
})
const control: DialogControl = {
get input() {
return store.input
},
get size() {
return store.size
},
get transition() {
return store.transition
},
isOpen(input) {
return store.dialog === input
},
open(component, input) {
setStore({
dialog: component,
input: input,
size: store.dialog !== undefined ? store.size : component.size,
transition: store.dialog !== undefined,
})
setTimeout(() => {
setStore({
size: component.size,
})
}, 0)
setTimeout(() => {
setStore({
transition: false,
})
}, 150)
},
close() {
setStore({
dialog: undefined,
})
},
}
return (
<>
<Context.Provider value={control}>{props.children}</Context.Provider>
</>
)
}
export function useDialog() {
const ctx = useContext(Context)
if (!ctx) {
throw new Error("useDialog must be used within a DialogProvider")
}
return ctx
}
-36
View File
@@ -1,36 +0,0 @@
.options {
margin-top: var(--space-1);
border-top: 2px solid var(--color-border);
padding: var(--space-2);
[data-slot="option"] {
outline: none;
flex-shrink: 0;
height: var(--space-11);
display: flex;
justify-content: start;
align-items: center;
padding: 0 var(--space-2-5);
gap: var(--space-3);
cursor: pointer;
&[data-empty] {
cursor: default;
color: var(--color-text-dimmed);
}
&[data-active] {
background-color: var(--color-bg-surface);
}
[data-slot="title"] {
font-size: var(--font-size-md);
}
[data-slot="prefix"] {
width: var(--space-4);
height: var(--space-4);
}
}
}
-124
View File
@@ -1,124 +0,0 @@
import style from "./dialog-select.module.css"
import { z } from "zod"
import { createMemo, createSignal, For, JSX, onMount } from "solid-js"
import { createList } from "solid-list"
import { createDialog } from "./context-dialog"
export const DialogSelect = createDialog({
size: "md",
schema: z.object({
title: z.string(),
placeholder: z.string(),
onSelect: z
.function(z.tuple([z.any()]))
.returns(z.void())
.optional(),
options: z.array(
z.object({
display: z.string(),
value: z.any().optional(),
onSelect: z.function().returns(z.void()).optional(),
prefix: z.custom<JSX.Element>().optional(),
}),
),
}),
render: (ctx) => {
let input: HTMLInputElement
onMount(() => {
input.focus()
input.value = ""
})
const [filter, setFilter] = createSignal("")
const filtered = createMemo(() =>
ctx.input.options?.filter((i) =>
i.display.toLowerCase().includes(filter().toLowerCase()),
),
)
const list = createList({
loop: true,
initialActive: 0,
items: () => filtered().map((_, i) => i),
handleTab: false,
})
const handleSelection = (index: number) => {
const option = ctx.input.options[index]
// If the option has its own onSelect handler, use it
if (option.onSelect) {
option.onSelect()
}
// Otherwise, if there's a global onSelect handler, call it with the option's value
else if (ctx.input.onSelect) {
ctx.input.onSelect(
option.value !== undefined ? option.value : option.display,
)
}
}
return (
<>
<div data-slot="header">
<label
data-size="md"
data-slot="title"
data-component="label"
for={`dialog-select-${ctx.input.title}`}
>
{ctx.input.title}
</label>
</div>
<div data-slot="main">
<input
data-size="lg"
data-component="input"
value={filter()}
onInput={(e) => {
setFilter(e.target.value)
list.setActive(0)
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
const selected = list.active()
if (selected === null) return
handleSelection(selected)
return
}
if (e.key === "Escape") {
setFilter("")
return
}
list.onKeyDown(e)
}}
id={`dialog-select-${ctx.input.title}`}
ref={(r) => (input = r)}
data-slot="input"
placeholder={ctx.input.placeholder}
/>
</div>
<div data-slot="options" class={style.options}>
<For
each={filtered()}
fallback={
<div data-slot="option" data-empty>
No results
</div>
}
>
{(option, index) => (
<div
onClick={() => handleSelection(index())}
data-slot="option"
data-active={list.active() === index() ? true : undefined}
>
{option.prefix && <div data-slot="prefix">{option.prefix}</div>}
<div data-slot="title">{option.display}</div>
</div>
)}
</For>
</div>
</>
)
},
})
-70
View File
@@ -1,70 +0,0 @@
import { z } from "zod"
import { onMount } from "solid-js"
import { createDialog } from "./context-dialog"
import { Button } from "./button"
export const DialogString = createDialog({
size: "sm",
schema: z.object({
title: z.string(),
placeholder: z.string(),
action: z.string(),
onSubmit: z.function().args(z.string()).returns(z.void()),
}),
render: (ctx) => {
let input: HTMLInputElement
onMount(() => {
setTimeout(() => {
input.focus()
input.value = ""
}, 50)
})
function submit() {
const value = input.value.trim()
if (value) {
ctx.input.onSubmit(value)
ctx.control.close()
}
}
return (
<>
<div data-slot="header">
<label
data-size="md"
data-slot="title"
data-component="label"
for={`dialog-string-${ctx.input.title}`}
>
{ctx.input.title}
</label>
</div>
<div data-slot="main">
<input
data-slot="input"
data-size="lg"
data-component="input"
ref={(r) => (input = r)}
placeholder={ctx.input.placeholder}
id={`dialog-string-${ctx.input.title}`}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault()
submit()
}
}}
/>
</div>
<div data-slot="footer">
<Button size="md" color="ghost" onClick={() => ctx.control.close()}>
Cancel
</Button>
<Button size="md" color="secondary" onClick={submit}>
{ctx.input.action}
</Button>
</div>
</>
)
},
})
-27
View File
@@ -1,27 +0,0 @@
import { Dialog as Kobalte } from "@kobalte/core/dialog"
import { ComponentProps, ParentProps } from "solid-js"
export type Props = ParentProps<{
size?: "sm" | "md"
transition?: boolean
}> &
ComponentProps<typeof Kobalte>
export function Dialog(props: Props) {
return (
<Kobalte {...props}>
<Kobalte.Portal>
<Kobalte.Overlay data-component="dialog-overlay" />
<div data-component="dialog-center">
<Kobalte.Content
data-transition={props.transition ? "" : undefined}
data-size={props.size}
data-slot="content"
>
{props.children}
</Kobalte.Content>
</div>
</Kobalte.Portal>
</Kobalte>
)
}
@@ -1,78 +0,0 @@
[data-component="button"] {
width: fit-content;
display: flex;
line-height: 1;
align-items: center;
justify-content: center;
gap: var(--space-2);
font-size: var(--font-size-md);
text-transform: uppercase;
height: var(--space-11);
outline: none;
font-weight: 500;
padding: 0 var(--space-4);
border-width: 2px;
border-color: var(--color-border);
cursor: pointer;
&:disabled {
opacity: 0.5;
cursor: default;
}
&[data-color="primary"] {
background-color: var(--color-text);
border-color: var(--color-text);
color: var(--color-text-invert);
&:active {
border-color: var(--color-accent);
}
}
&[data-color="secondary"] {
&:active {
border-color: var(--color-accent);
}
}
&[data-color="ghost"] {
border: none;
text-decoration: underline;
&:active {
color: var(--color-text-accent);
}
}
&:has([data-slot="icon"]) {
padding-left: var(--space-3);
padding-right: var(--space-3);
}
&[data-size="sm"] {
height: var(--space-8);
padding: var(--space-3);
font-size: var(--font-size-xs);
[data-slot="icon"] {
width: var(--space-3-5);
height: var(--space-3-5);
}
&:has([data-slot="icon"]) {
padding-left: var(--space-2);
padding-right: var(--space-2);
}
}
[data-slot="icon"] {
width: var(--space-4);
height: var(--space-4);
transition: transform 0.2s ease;
}
&[data-rotate] [data-slot="icon"] {
transform: rotate(180deg);
}
}
@@ -1,84 +0,0 @@
[data-component="dialog-overlay"] {
pointer-events: none !important;
position: fixed;
inset: 0;
animation-name: fadeOut;
animation-duration: 200ms;
animation-timing-function: ease;
opacity: 0;
backdrop-filter: blur(2px);
&[data-expanded] {
animation-name: fadeIn;
opacity: 1;
pointer-events: auto !important;
}
}
[data-component="dialog-center"] {
position: fixed;
inset: 0;
padding-top: 10vh;
justify-content: center;
pointer-events: none;
[data-slot="content"] {
width: 45rem;
margin: 0 auto;
transition: 150ms width;
background-color: var(--color-bg);
border-width: 2px;
border-color: var(--color-border);
overflow: hidden;
display: flex;
flex-direction: column;
gap: var(--space-3);
outline: none;
animation-duration: 1ms;
animation-name: zoomOut;
animation-timing-function: ease;
box-shadow: 8px 8px 0px 0px var(--color-gray-4);
&[data-expanded] {
animation-name: zoomIn;
}
&[data-transition] {
animation-duration: 200ms;
}
&[data-size="sm"] {
width: 30rem;
}
[data-slot="header"] {
display: flex;
padding: var(--space-4) var(--space-4) 0;
[data-slot="title"] {
}
}
[data-slot="main"] {
padding: 0 var(--space-4);
&:has([data-slot="options"]) {
padding: 0;
display: flex;
flex-direction: column;
gap: var(--space-4);
}
}
[data-slot="input"] {
}
[data-slot="footer"] {
padding: var(--space-4);
display: flex;
gap: var(--space-4);
justify-content: end;
}
}
}
@@ -1,34 +0,0 @@
[data-component="input"] {
font-size: var(--font-size-md);
background: transparent;
caret-color: var(--color-accent);
font-family: var(--font-mono);
height: var(--space-11);
padding: 0 var(--space-4);
width: 100%;
resize: none;
border: 2px solid var(--color-border);
&::placeholder {
color: var(--color-text-dimmed);
opacity: 0.75;
}
&:focus {
outline: 0;
}
&[data-size="sm"] {
height: var(--space-9);
padding: 0 var(--space-3);
font-size: var(--font-size-xs);
}
&[data-size="md"] {
}
&[data-size="lg"] {
height: var(--space-12);
font-size: var(--font-size-lg);
}
}
@@ -1,17 +0,0 @@
[data-component="label"] {
letter-spacing: -0.03125rem;
text-transform: uppercase;
color: var(--color-text-dimmed);
font-weight: 500;
font-size: var(--font-size-md);
&[data-size="sm"] {
font-size: var(--font-size-sm);
}
&[data-size="md"] {
}
&[data-size="lg"] {
font-size: var(--font-size-lg);
}
}
@@ -1,32 +0,0 @@
[data-component="title-bar"] {
display: flex;
align-items: center;
justify-content: space-between;
height: 72px;
padding: 0 var(--space-4);
border-bottom: 2px solid var(--color-border);
[data-slot="left"] {
display: flex;
flex-direction: column;
gap: var(--space-1-5);
h1 {
letter-spacing: -0.03125rem;
font-size: var(--font-size-xl);
text-transform: uppercase;
font-weight: 600;
}
p {
color: var(--color-text-dimmed);
}
}
}
@media (max-width: 40rem) {
[data-component="title-bar"] {
display: none;
}
}
-50
View File
@@ -1,50 +0,0 @@
/* tokens */
@import "./token/color.css";
@import "./token/reset.css";
@import "./token/animation.css";
@import "./token/font.css";
@import "./token/space.css";
/* components */
@import "./component/label.css";
@import "./component/input.css";
@import "./component/button.css";
@import "./component/dialog.css";
@import "./component/title-bar.css";
body {
font-family: var(--font-mono);
line-height: 1;
color: var(--color-text);
background-color: var(--color-bg);
cursor: default;
user-select: none;
text-underline-offset: 0.1875rem;
}
a {
text-decoration: underline;
&:active {
color: var(--color-text-accent);
}
}
::selection {
background-color: var(--color-text-accent-invert);
}
/* Responsive utilities */
[data-max-width] {
width: 100%;
& > * {
max-width: 90rem;
margin-left: auto;
margin-right: auto;
width: 100%;
}
&[data-max-width-64] > * {
max-width: 64rem;
}
}
@@ -1,23 +0,0 @@
@keyframes zoomIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes zoomOut {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.95);
}
}
-88
View File
@@ -1,88 +0,0 @@
:root {
--color-white: hsl(0, 0%, 100%);
--color-gray-1: hsl(224, 20%, 94%);
--color-gray-2: hsl(224, 6%, 77%);
--color-gray-3: hsl(224, 6%, 56%);
--color-gray-4: hsl(224, 7%, 36%);
--color-gray-5: hsl(224, 10%, 23%);
--color-gray-6: hsl(224, 14%, 16%);
--color-black: hsl(224, 10%, 10%);
--hue-orange: 41;
--color-orange-low: hsl(var(--hue-orange), 39%, 22%);
--color-orange: hsl(var(--hue-orange), 82%, 63%);
--color-orange-high: hsl(var(--hue-orange), 82%, 87%);
--hue-green: 101;
--color-green-low: hsl(var(--hue-green), 39%, 22%);
--color-green: hsl(var(--hue-green), 82%, 63%);
--color-green-high: hsl(var(--hue-green), 82%, 80%);
--hue-blue: 234;
--color-blue-low: hsl(var(--hue-blue), 54%, 20%);
--color-blue: hsl(var(--hue-blue), 100%, 60%);
--color-blue-high: hsl(var(--hue-blue), 100%, 87%);
--hue-purple: 281;
--color-purple-low: hsl(var(--hue-purple), 39%, 22%);
--color-purple: hsl(var(--hue-purple), 82%, 63%);
--color-purple-high: hsl(var(--hue-purple), 82%, 89%);
--hue-red: 339;
--color-red-low: hsl(var(--hue-red), 39%, 22%);
--color-red: hsl(var(--hue-red), 82%, 63%);
--color-red-high: hsl(var(--hue-red), 82%, 87%);
--color-accent-low: hsl(13, 75%, 30%);
--color-accent: hsl(13, 88%, 57%);
--color-accent-high: hsl(13, 100%, 78%);
--color-text: var(--color-gray-1);
--color-text-dimmed: var(--color-gray-3);
--color-text-accent: var(--color-accent);
--color-text-invert: var(--color-black);
--color-text-accent-invert: var(--color-accent-high);
--color-bg: var(--color-black);
--color-bg-surface: var(--color-gray-5);
--color-bg-accent: var(--color-accent-high);
--color-border: var(--color-gray-2);
--color-backdrop-overlay: hsla(223, 13%, 10%, 0.66);
}
:root[data-color-mode="light"] {
--color-white: hsl(224, 10%, 10%);
--color-gray-1: hsl(224, 14%, 16%);
--color-gray-2: hsl(224, 10%, 23%);
--color-gray-3: hsl(224, 7%, 36%);
--color-gray-4: hsl(224, 6%, 56%);
--color-gray-5: hsl(224, 6%, 77%);
--color-gray-6: hsl(224, 20%, 94%);
--color-gray-7: hsl(224, 19%, 97%);
--color-black: hsl(0, 0%, 100%);
--color-orange-high: hsl(var(--hue-orange), 80%, 25%);
--color-orange: hsl(var(--hue-orange), 90%, 60%);
--color-orange-low: hsl(var(--hue-orange), 90%, 88%);
--color-green-high: hsl(var(--hue-green), 80%, 22%);
--color-green: hsl(var(--hue-green), 90%, 46%);
--color-green-low: hsl(var(--hue-green), 85%, 90%);
--color-blue-high: hsl(var(--hue-blue), 80%, 30%);
--color-blue: hsl(var(--hue-blue), 90%, 60%);
--color-blue-low: hsl(var(--hue-blue), 88%, 90%);
--color-purple-high: hsl(var(--hue-purple), 90%, 30%);
--color-purple: hsl(var(--hue-purple), 90%, 60%);
--color-purple-low: hsl(var(--hue-purple), 80%, 90%);
--color-red-high: hsl(var(--hue-red), 80%, 30%);
--color-red: hsl(var(--hue-red), 90%, 60%);
--color-red-low: hsl(var(--hue-red), 80%, 90%);
--color-accent-high: hsl(13, 75%, 26%);
--color-accent: hsl(13, 88%, 60%);
--color-accent-low: hsl(13, 100%, 89%);
--color-text-accent: var(--color-accent);
--color-text-dimmed: var(--color-gray-4);
--color-text-invert: var(--color-black);
--color-text-accent-invert: var(--color-accent-low);
--color-bg-surface: var(--color-gray-6);
--color-bg-accent: var(--color-accent);
--color-backdrop-overlay: hsla(225, 9%, 36%, 0.66);
}
-20
View File
@@ -1,20 +0,0 @@
:root {
--font-size-2xs: 0.6875rem;
--font-size-xs: 0.75rem;
--font-size-sm: 0.8125rem;
--font-size-md: 0.9375rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-size-3xl: 1.875rem;
--font-size-4xl: 2.25rem;
--font-size-5xl: 3rem;
--font-size-6xl: 3.75rem;
--font-size-7xl: 4.5rem;
--font-size-8xl: 6rem;
--font-size-9xl: 8rem;
--font-mono: IBM Plex Mono, monospace;
--font-sans: Rubik, sans-serif;
--font-line-height: 1.75;
}

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