Compare commits

..

1050 Commits

Author SHA1 Message Date
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
opencode 3a994c4919 release: v0.5.10 2025-08-20 16:12:00 +00:00
opencode 5a141f61f7 release: v0.5.9 2025-08-20 15:51:24 +00:00
Dax Raad d481a905ea copilot auth update version 2025-08-20 11:46:14 -04:00
GitHub Action 011a1fce12 ignore: update download stats 2025-08-20 2025-08-20 12:04:23 +00:00
opencode 4ab267084b release: v0.5.8 2025-08-20 05:08:31 +00:00
Dax Raad f69816302b sonic model 2025-08-20 01:02:41 -04:00
Aiden Cline 3c1e9c3498 fix: don't let --continue access subagent session (#2091) 2025-08-19 22:40:07 -05:00
Aiden Cline d1f4a2ec6a fix: keybind panic (#2092) 2025-08-19 22:39:59 -05:00
Aiden Cline 7e4284152b fix: agent casing issue (#2081) 2025-08-19 18:08:56 -05:00
Aiden Cline d4eae43857 docs: remove non existent keybind (#2080) 2025-08-19 17:39:02 -05:00
Jay V 22b0332ccb docs: add sdk doc 2025-08-19 18:11:36 -04:00
Jay V 0f6a8a641b docs: edit server 2025-08-19 17:21:45 -04:00
Aiden Cline 2ef0c3c1fb tweak: notify agent it is in build mode when switching from plan mode (#2065) 2025-08-19 15:32:31 -05:00
Timo Clasen 0af6bd06ce fix(TUI): make it less shimmer (#2076) 2025-08-19 15:30:54 -05:00
Zack Jackson 9e01bc7307 docs: document server API endpoints (#2019)
Co-authored-by: Jay <air@live.ca>
2025-08-19 16:13:02 -04:00
Aiden Cline 5342d540df fix: tui panic from logger (#2075) 2025-08-19 14:47:44 -05:00
Aiden Cline a91e034cf0 fix: add type checking for MCP tool path parameters (#2073)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
2025-08-19 13:38:33 -05:00
GitHub Action a6987e3500 ignore: update download stats 2025-08-19 2025-08-19 12:04:15 +00:00
Aiden Cline 2f802244e3 fix: interface conversion panic (#2060) 2025-08-19 05:25:46 -05:00
Aiden Cline 3c1194d83b tweak: better agent create error handling (#2058) 2025-08-19 00:14:50 -05:00
Dax 58e16020d7 Update duplicate-issues.yml 2025-08-18 20:00:59 -04:00
Aiden Cline b84482f17a fix: ensure name isn't added as field in options: {...} (#2053) 2025-08-18 18:15:20 -05:00
Aiden Cline 7ed4a97ad2 blacklist gpt-5-chat-latest (#2048) 2025-08-18 17:50:38 -04:00
opencode b86ac479b3 release: v0.5.7 2025-08-18 21:43:17 +00:00
Dax 82ac58da90 fix anthropic console auth (#2049) 2025-08-18 17:12:21 -04:00
Jay V 3ff9679e61 docs:edit 2025-08-18 13:52:53 -04:00
Jay V 75d65db74c docs:edit 2025-08-18 13:51:08 -04:00
Jay V 4dc18cf722 docs: edits 2025-08-18 13:31:01 -04:00
Jay V 9e5ce2160a docs: add tui doc 2025-08-18 13:31:01 -04:00
opencode 2b909c9fbc release: v0.5.6 2025-08-18 15:56:22 +00:00
John Connor 70475aa19c Remove redundant line from agents.mdx (#2031) 2025-08-18 08:34:57 -05:00
GitHub Action 472aaa2ae7 ignore: update download stats 2025-08-18 2025-08-18 12:04:33 +00:00
adamdotdevin 7f9f277948 fix(tui): title bg color missing on system theme 2025-08-18 06:00:38 -05:00
Ytzhak e69bc53ecc feat: add shimmer text rendering (#2027) 2025-08-18 05:55:01 -05:00
spoons-and-mirrors dbf12e634f tweak(timeline): add a dot to the session timeline modal for better visual cue of session's revert point (#1978) 2025-08-18 05:50:43 -05:00
Frank 2215e2b530 sync 2025-08-18 07:58:46 +00:00
Frank 83d5cc23fe Squashed commit of the following:
publish-github-action / publish (push) Waiting to run
commit 7b2ad6a1abf88e0731f15bbf6e281b29a610dd76
Merge: 74c85391 7aab18cb
Author: Frank <frank@sst.dev>
Date:   Mon Aug 18 15:31:54 2025 +0800

    Merge branch 'dev' into github

commit 74c85391b576d01df298f6c30e3399b281b5c997
Author: Frank <frank@sst.dev>
Date:   Mon Aug 18 15:30:14 2025 +0800

    sync

commit 0d27f8e490f1aa242e1a3fcd1f21eb077f852207
Author: Frank <frank@sst.dev>
Date:   Mon Aug 18 14:30:57 2025 +0800

    sync

commit 0cf7e6c89f173b053f37cc0d316011b3e9d5fcc4
Author: Frank <frank@sst.dev>
Date:   Mon Aug 18 11:54:57 2025 +0800

    sync

commit a782cb7a268bf98916c3850083eaf44ebc38de05
Author: Frank <frank@sst.dev>
Date:   Mon Aug 18 11:53:25 2025 +0800

    sync

commit aa557014584abaf462656ba9b1de7c8bd6e9b9d8
Author: Frank <frank@sst.dev>
Date:   Mon Aug 18 11:48:10 2025 +0800

    sync

commit 73c8150479bd3c965087c634102df047a36b40ab
Author: Frank <frank@sst.dev>
Date:   Mon Aug 18 01:29:29 2025 +0800

    sync

commit c5325134e80ce3f9e2cb88e5a51893e4ffd880c2
Author: Frank <frank@sst.dev>
Date:   Mon Aug 18 01:07:48 2025 +0800

    sync

commit c5b646aa88760731ac9cd221f677bd400c31224b
Author: Frank <frank@sst.dev>
Date:   Mon Aug 18 01:02:02 2025 +0800

    sync

commit 27f7cc86ab4713a26d316ae71d2aa5978aaa2007
Author: Frank <frank@sst.dev>
Date:   Mon Aug 18 00:59:22 2025 +0800

    sync

commit 0a6152a0e0c2bb0e5b7cafbcb92b908433dd6c5b
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 18:11:31 2025 +0800

    fix /opencode trigger

commit f1089103c607ac11251cac5e032e62c8b4667b30
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 17:55:14 2025 +0800

    sync

commit 3ad18240248301380a68880315bfa83c18e9652d
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 17:44:11 2025 +0800

    sync

commit 24f0f81773762a38ba0a26e599b718495e2f4b54
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 17:18:22 2025 +0800

    sync

commit bc199d32bed9679d2f80ade527fa57a91e0883ca
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 16:59:03 2025 +0800

    sync

commit 6cf860be843e94401166a6de83e36d6bdd8ca6d7
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 16:54:48 2025 +0800

    sync

commit f5f753ff38498062b2e3de38a1be94158fce1463
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 14:43:12 2025 +0800

    sync

commit 26d2e23a3ee99141a5951a153e444a1be25548dc
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 14:33:40 2025 +0800

    sync

commit c5b3f54a0ae6064ff51c11ade41e21b594939715
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 14:16:10 2025 +0800

    sync

commit 1c74e9a7ad35551eea53d0e51dcd28e6ae30a944
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 08:17:53 2025 +0800

    sync

commit 89052dc9aaf7e4f02b7ca869ef6017322ee21c94
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 08:12:43 2025 +0800

    sync

commit 42931d4d2a942eedef44f5570a57bf84df26ecfa
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 08:08:37 2025 +0800

    sync

commit f22e97dd051ae3f592f4258a8d0270ca7fd60338
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 08:01:57 2025 +0800

    sync

commit 2dda422ef85d2308b459cebe7f202b7fb782e75e
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 07:55:38 2025 +0800

    sync

commit b8be1d0e9e89732bd60185c724cda72b8de5f145
Author: Frank <frank@sst.dev>
Date:   Sun Aug 17 07:48:18 2025 +0800

    sync

commit 78c84b96a3c8aa78e0ffa089a2a72ad80348fe72
Author: Frank <frank@sst.dev>
Date:   Sat Aug 16 20:49:26 2025 +0800

    sync

commit dd9c0c83090ea6c5da963303227a1e09a8434994
Author: Frank <frank@sst.dev>
Date:   Sat Aug 16 20:47:25 2025 +0800

    sync

commit 5eb917abba182712d1581376e95de45a092bbb24
Author: Frank <frank@sst.dev>
Date:   Sat Aug 16 20:35:48 2025 +0800

    sync

commit 43cf83e7ccbc99484602b06cbb6aafdbc63bf11c
Author: Frank <frank@sst.dev>
Date:   Sat Aug 16 20:32:49 2025 +0800

    sync

commit 10673ca3d2e1572e15c944ddd7d7af8175971f74
Author: Frank <frank@sst.dev>
Date:   Sat Aug 16 19:55:53 2025 +0800

    sync

commit c45ae8a233ed64c49a08b98f3ad01e0348b2df22
Author: Frank <frank@sst.dev>
Date:   Sat Aug 16 19:53:52 2025 +0800

    sync

commit 3c329dee05ecda95f5d249552aafc885997f07f2
Author: Frank <frank@sst.dev>
Date:   Sat Aug 16 19:49:56 2025 +0800

    sync

commit 5797048db864142f15d73c854131a77a31a421ee
Author: Frank <frank@sst.dev>
Date:   Sat Aug 16 18:00:04 2025 +0800

    sync

commit 2741338e8a27e57d9d023cf9c0a6a05276b82f41
Author: Frank <frank@sst.dev>
Date:   Sat Aug 16 17:54:42 2025 +0800

    sync

commit a51a8ca6d094bd5f98330c730d335285688c6ed8
Author: Frank <frank@sst.dev>
Date:   Fri Aug 15 18:59:29 2025 +0800

    sync

commit f4eeeb612dfa6f1714a954dd167519ade0c36a2d
Author: Frank <frank@sst.dev>
Date:   Fri Aug 15 18:56:35 2025 +0800

    sync

commit 1d0509c5630904a5a9e89ce0de09fbebb6f711be
Author: Frank <frank@sst.dev>
Date:   Fri Aug 15 18:54:21 2025 +0800

    sync

commit 339807d1b88d2439e9543b5da4ca2538a49f4ab8
Author: Frank <frank@sst.dev>
Date:   Fri Aug 15 18:49:22 2025 +0800

    sync

commit 70b4b78922fe80424d8922bb999ed84d28dff005
Author: Frank <frank@sst.dev>
Date:   Fri Aug 15 18:04:57 2025 +0800

    sync
2025-08-18 15:34:28 +08:00
Aiden Cline 7aab18cb27 fix: gh install trim remote origin (#2030) 2025-08-17 22:45:22 -05:00
Aiden Cline 68b2a02e14 fix: better binary file detection (#2025) 2025-08-17 17:59:51 -05:00
GitHub Action d54b377650 ignore: update download stats 2025-08-17 2025-08-17 12:03:50 +00:00
Thierry Delafontaine 831794f2cb fix(opencode): add ulid dependency (#1988) (#1989)
Co-authored-by: Dax <mail@thdxr.com>
2025-08-16 23:21:29 -04:00
Lucas ebaa529b20 feat(lsp): add rust-analyzer (#1972) 2025-08-16 22:59:51 -04:00
Aiden Cline 27946fceeb fix: lsp bug (#1994) 2025-08-16 22:59:18 -04:00
Aiden Cline 7ca223491e fix: install script didnt use -e flag (#2009) 2025-08-16 22:55:49 -04:00
spoons-and-mirrors 2b53a043a6 tweak(config): make markdown agent files in subfolder discoverable .opencode/agent/some-folder/*.md (#1999) 2025-08-16 22:55:14 -04:00
Aiden Cline 30c17d9544 feat: top level tool config (#2008) 2025-08-16 22:51:56 -04:00
Aiden Cline 21c2348199 docs: more troubleshooting examples (#2004) 2025-08-16 19:33:49 -05:00
opencode 59f368e6b3 release: v0.5.5 2025-08-16 15:00:04 +00:00
Yihui Khuu a4112e1f91 fix(tui): text selection is sometimes not cleared when click+release without dragging (#1993) 2025-08-16 09:16:09 -05:00
Yihui Khuu b28f3c90ab feat(tui): retain cache when cycling between subagent/parent sessions for perf (#1981) 2025-08-16 08:58:13 -05:00
Aiden Cline f7dff48947 tweak: plan prompt, more explicit about not modifying files (#1991) 2025-08-16 08:56:43 -05:00
GitHub Action 2fad74078d ignore: update download stats 2025-08-16 2025-08-16 12:03:50 +00:00
Aiden Cline bd3db58e7f fix: remove unsupported mode flag, change to agent (#1979) 2025-08-15 22:02:06 -05:00
Dax Raad edc8d3b1c3 wip: cloud 2025-08-15 19:50:46 -04:00
Dax Raad 691684f628 wip: fix CSS syntax issues in index.css 2025-08-15 19:42:50 -04:00
Dax Raad 9fbe04b3fa wip: replace hardcoded spacing and font values with design tokens 2025-08-15 19:39:34 -04:00
Dax Raad 37a4c9c4a7 wip: agent css 2025-08-15 19:34:45 -04:00
Dax Raad 3f97600c9a wip: css agent 2025-08-15 19:32:32 -04:00
Dax Raad 80233149c6 wip: cloud stuff 2025-08-15 19:29:42 -04:00
opencode ab04ce97f6 release: v0.5.4 2025-08-15 22:52:49 +00:00
Aiden Cline 4d3f44d8b5 tweak: fix scroll speed (#1974) 2025-08-15 16:19:58 -05:00
Timo Clasen bbb9eb80b4 fix: run command (#1971) 2025-08-15 15:58:20 -05:00
opencode 24d26c484e release: v0.5.3 2025-08-15 18:56:32 +00:00
adamdotdevin 0be1a86db9 fix: some visual bugs in dialogs 2025-08-15 13:50:54 -05:00
Yihui Khuu 03e7829394 feat(shell): load .zshenv and respect ZDOTDIR if present (#1958) 2025-08-15 13:24:34 -05:00
Yihui Khuu 74bf6028fa fix(shell): commands expecting stdin will be "working" indefinitely (#1964) 2025-08-15 13:23:59 -05:00
spoons-and-mirrors 3a21e5e10f feat(TUI): improves UX with message navigation modal to jump and restore to specific messages (#1969) 2025-08-15 13:23:21 -05:00
Aiden Cline 0d6342bd7f feat: add scroll speed to config (#1968) 2025-08-15 13:21:02 -05:00
opencode cde0b252ac release: v0.5.2 2025-08-15 15:22:21 +00:00
adamdotdevin dddc968bb2 feat(tui): navigate child sessions (subagents) 2025-08-15 10:16:08 -05:00
adamdotdevin 327cdea30b feat(api): get session and session children routes 2025-08-15 08:49:19 -05:00
adamdotdevin 6369bb9130 feat: /tui/show-toast api 2025-08-15 08:39:58 -05:00
adamdotdevin d258ad2aa9 fix: more commands cleanup 2025-08-15 07:43:30 -05:00
GitHub Action fe0c35a017 ignore: update download stats 2025-08-15 2025-08-15 12:04:27 +00:00
adamdotdevin d4d00e3e31 feat: better queued visual 2025-08-15 06:55:16 -05:00
adamdotdevin 8a95a0f288 fix: keybind docs out of sync 2025-08-15 06:45:20 -05:00
adamdotdevin 81cd149cc1 chore: deprecate unused keybinds 2025-08-15 06:36:28 -05:00
adamdotdevin 6e7a8cfb2f fix: add missing keybinds to config 2025-08-15 06:33:45 -05:00
Yihui Khuu 09ec4b5750 fix(tui): issue with rendering markdown tables (#1956) 2025-08-15 06:21:08 -05:00
Yihui Khuu 3554fff446 feat(tui): support cycling recent models in reverse (#1953) 2025-08-15 06:20:07 -05:00
Andre van Tonder d7cf22610e Add Vue LSP and enable eslint for .vue files. (#1952) 2025-08-15 06:18:27 -05:00
Mariano Uvalle 3f1eec0747 Feat: Render tool metadata after permission rejection. (#1949)
Signed-off-by: jmug <u.g.a.mariano@gmail.com>
2025-08-15 06:16:40 -05:00
Aiden Cline 631e2074f3 fix: more permissive owner/repo detection (#1948) 2025-08-15 06:11:41 -05:00
Aiden Cline f056ad2494 fix: fish shell (#1950) 2025-08-15 06:11:09 -05:00
Frank 3e43f174be Docs: update z.ai provider doc 2025-08-15 15:52:00 +08:00
Timo Clasen a7ce33a024 fix(TUI): fix agent types agents modal (#1942) 2025-08-14 17:58:44 -05:00
Jay V 79904bdafb lander: match alternatives h3 font size with figcaption on mobile 2025-08-14 18:55:07 -04:00
Aiden Cline e07e28e5b5 fix: small tweak to support nushell (#1943) 2025-08-14 17:54:22 -05:00
Jay V d8fe40f939 ignore: lander 2025-08-14 17:19:14 -04:00
opencode 5f81e4d2e4 release: v0.5.1 2025-08-14 20:47:45 +00:00
Dax Raad f8100a6dbd ci: aur is down 2025-08-14 16:42:39 -04:00
Dax Raad ba30792e43 allow plugins to create custom auth providers 2025-08-14 16:25:08 -04:00
Jay V 42d1f13085 ignore: lander tweaks 2025-08-14 15:53:41 -04:00
Jay V 50272c33e2 ignore: lander styles 2025-08-14 15:53:41 -04:00
Dax Raad f49bd6081e wip: sdk 2025-08-14 12:22:27 -04:00
Dax Raad ea2e67f54a ci: tweak 2025-08-14 12:20:22 -04:00
Dax Raad b4c81830db fix for session stuck in "Working..." 2025-08-14 12:20:22 -04:00
Lubos d6015bab27 chore: declare OpenAPI version 3.1.1 (#1931) 2025-08-14 12:10:32 -04:00
GitHub Action fbfc1dae71 ignore: update download stats 2025-08-14 2025-08-14 12:04:42 +00:00
Aiden Cline d1c2011cb7 fix: support fish shell (#1911) 2025-08-13 20:04:04 -05:00
Aiden Cline 3f095d6682 docs: fix bad example (#1913) 2025-08-13 20:03:44 -05:00
opencode 066419436f release: v0.4.45 2025-08-13 22:32:26 +00:00
Aiden Cline 18dbb56040 fix: bash should hide stdout from zshrc (#1909) 2025-08-13 17:04:32 -04:00
adamdotdevin a8b798a18f chore: rename bash -> shell 2025-08-13 15:11:30 -05:00
Yuu Toriyama 7ef8f34c1b Fix: Error [ERR_DLOPEN_FAILED] (#1546) 2025-08-13 19:49:14 +00:00
opencode bef91d3af6 release: v0.4.44 2025-08-13 19:49:14 +00:00
Dax Raad c5a7a2c790 re-enable aur 2025-08-13 15:44:11 -04:00
Dax Raad e1a8354298 ci: issue 2025-08-13 15:43:06 -04:00
envolution 46b0674d30 Fix incorrect AUR namespace (#1907) 2025-08-13 15:37:15 -04:00
adamdotdevin 2041db6a52 fix: default scroll speed should be slower 2025-08-13 14:35:18 -05:00
Dax Raad db434176bf docs: fix 2025-08-13 19:33:38 +00:00
Dominik Engelhardt 7208872450 feat: convert attachments to text on delete (#1863)
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Dax <mail@thdxr.com>
2025-08-13 19:33:38 +00:00
opencode 0aebc7bd51 release: v0.4.43 2025-08-13 19:33:38 +00:00
Dax Raad 7b78ee7688 support !shell commands 2025-08-13 15:26:13 -04:00
adamdotdevin 1d30b9260f feat: bash commands 2025-08-13 13:28:22 -05:00
Dax Raad fa004648c4 wip: bash 2025-08-13 14:14:27 -04:00
Jay V 2d599e8303 docs: global model options 2025-08-13 14:07:10 -04:00
Dax Raad 9956073e38 docs(cli): document ! bash commands and session persistence in CLI docs 2025-08-13 13:37:19 -04:00
Dax Raad bed043b156 wip: bash 2025-08-13 13:31:29 -04:00
Dax Raad a27799a187 wip: bash commands 2025-08-13 13:29:06 -04:00
Matt Cook 15caad5835 fix: grammatical error in agent launch example (by Opencode) (#1897) 2025-08-13 12:25:38 -05:00
Aiden Cline 530b7b092a fix: js plugin support as per documentation (#1896) 2025-08-13 12:25:04 -05:00
Aiden Cline e473ed147d fix: duplicates bot prompt (#1901) 2025-08-13 11:54:37 -05:00
opencode ba36f1b325 release: v0.4.42 2025-08-13 16:48:35 +00:00
adamdotdevin 4ae74882c0 fix: messages layout instability 2025-08-13 11:43:28 -05:00
adamdotdevin 565ff387fe fix: allow attachments outside cwd, and support svg 2025-08-13 10:36:50 -05:00
adamdotdevin bf7fd99b2a fix: update read tool description to exclude binary/image files 2025-08-13 10:13:57 -05:00
Mariano Uvalle bd97c565c9 Merge default agent permissions with global config (#1879) 2025-08-13 09:01:17 -04:00
GitHub Action 8c9855e28d ignore: update download stats 2025-08-13 2025-08-13 12:04:41 +00:00
Aiden Cline 978e8f4c48 fix: permission prompting issues (#1884) 2025-08-13 06:34:06 -05:00
Aiden Cline 0d7f3dedeb fix: reasoning not supported (#1882) 2025-08-13 06:26:07 -05:00
Aiden Cline 71b2eed2d9 fix: task tool prompt (#1887) 2025-08-12 23:41:12 -04:00
Dax Raad 8aa3309087 ci: disable 2025-08-12 22:55:57 -04:00
Aiden Cline b73ec26a1a fix: better error message when config has invalid references (#1874) 2025-08-12 19:28:41 -05:00
opencode d08dff00d6 release: v0.4.41 2025-08-13 00:05:51 +00:00
Dax Raad ebd5b7a36c update copilot prompt 2025-08-12 20:01:34 -04:00
Dax Raad ece8dc3212 fix unzip not found printing to tui 2025-08-12 18:43:24 -04:00
opencode a917ba085c release: v0.4.40 2025-08-12 21:51:19 +00:00
Dax Raad 13c1b5ea6a ci: sync 2025-08-12 17:47:04 -04:00
Dax Raad c1c53564ba ci: disable AUR packaging in publish workflow 2025-08-12 17:44:39 -04:00
spoons-and-mirrors 7ad47bcc01 fix(TUI): unsurfacing subagent from agents modal (#1873) 2025-08-12 17:38:35 -04:00
Dax Raad fea9cc399a add openai prompt cache key 2025-08-12 17:37:15 -04:00
Dax Raad 81f087c9b3 ci: enable aur 2025-08-12 17:29:10 -04:00
Tom Hackshaw 551a91ebe6 chore: spelling in git committer file (#1869) 2025-08-12 16:29:41 -04:00
spoons-and-mirrors 8ee6dee6ff feat: add session rename functionality to TUI modal (#1821)
Co-authored-by: opencode <noreply@opencode.ai>
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Dax <mail@thdxr.com>
2025-08-12 16:22:03 -04:00
spoons-and-mirrors d5f4f56630 refactor(agent-modal): revamped UI/UX for the agent modal (#1838)
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Dax <mail@thdxr.com>
2025-08-12 16:21:57 -04:00
Dax Raad 42d2410553 bash truncate character max instead of line max 2025-08-12 16:14:40 -04:00
Dax Raad 2d4cb099fa ci: sync 2025-08-12 15:09:21 -04:00
Dax Raad 15fb3d7607 disable todo tools for qwen models to improve compatibility 2025-08-12 18:56:26 +00:00
opencode 287588cb22 release: v0.4.37 2025-08-12 18:56:25 +00:00
Dax Raad b5fe770876 limit bash tool to 1000 lines of output 2025-08-12 14:51:13 -04:00
Dax Raad cebe8ccd8c ci: sync 2025-08-12 14:38:58 -04:00
Dax Raad 4429ce7998 ci: sync 2025-08-12 14:33:09 -04:00
opencode 33a45a6b22 release: v0.4.36 2025-08-12 18:31:12 +00:00
adamdotdevin e08d5998da fix: markdown lists 2025-08-12 13:22:28 -05:00
Dax Raad b444740fe4 ci: sync 2025-08-12 14:21:34 -04:00
Dax Raad ac53a55cc9 ci: sync 2025-08-12 14:17:18 -04:00
Dax Raad 3161c0b001 ci: sync 2025-08-12 14:11:10 -04:00
adamdotdevin a32ee242ae fix: word wrapping with hyphens 2025-08-12 13:03:35 -05:00
Dax Raad 7a169f6fdb ci: sync 2025-08-12 14:00:30 -04:00
Dax Raad dc017bc5b2 ci: sync 2025-08-12 13:58:51 -04:00
Dax Raad 9ed2249163 ci: ignore 2025-08-12 13:54:53 -04:00
Dax Raad b50de8d056 ci: tweak 2025-08-12 13:53:32 -04:00
Dax Raad 67505a3d1a ci: sync 2025-08-12 13:42:46 -04:00
Dax Raad b1c497b94b ci: softer language 2025-08-12 13:39:53 -04:00
Dax Raad a57b9cd3f6 ci: sync 2025-08-12 17:36:48 +00:00
opencode 1ae5bdfef5 release: v0.4.35 2025-08-12 17:36:48 +00:00
Dax Raad 39c18fbf94 ci: ignore 2025-08-12 13:31:23 -04:00
Dax Raad 804ac4f237 fix issue when @ tagging fiels throwing error 2025-08-12 13:30:52 -04:00
Dax Raad 8a46c6d00d ci: ignore 2025-08-12 13:25:05 -04:00
Dax 9ae2519046 ci: improve guideline check (#1867) 2025-08-12 13:23:19 -04:00
opencode 778f83d5d0 release: v0.4.34 2025-08-12 17:14:23 +00:00
Dax Raad 1925d939c2 ci: sync 2025-08-12 13:09:24 -04:00
Dax Raad 73a722b5c2 ci: tweak 2025-08-12 13:01:45 -04:00
Dax Raad 2a09d9468f ci: disable aur 2025-08-12 12:58:18 -04:00
Dax Raad 5e883c3bf2 ci: sync 2025-08-12 12:53:55 -04:00
Dax Raad 36a64eecd2 ci: ignore 2025-08-12 12:33:10 -04:00
Dax Raad e2c02b1518 support OPENCODE_PERMISSION json env variable 2025-08-12 12:28:08 -04:00
Dax Raad 442c65f8ef ci: ignore 2025-08-12 12:12:54 -04:00
Dax 2a13b1b81e Add agent-level permissions with whitelist/blacklist support (#1862) 2025-08-12 11:39:39 -04:00
adamdotdevin 95ced9f6b6 fix: long word and attachment wrapping in editor 2025-08-12 10:34:54 -05:00
opencode 916dc4ef12 release: v0.4.29 2025-08-12 14:00:15 +00:00
Aiden Cline e53f6a9e78 fix: Missing ~/.local/share/opencode/bin directory causes misleading … (#1860) 2025-08-12 13:54:33 +00:00
opencode 233f6e0644 release: v0.4.28 2025-08-12 13:54:32 +00:00
adamdotdevin 85487d2f48 fix: vscode extension cursor placement 2025-08-12 08:48:42 -05:00
opencode 868a2f0b29 release: v0.4.27 2025-08-12 12:58:53 +00:00
adamdotdevin 8ee48dd4cd fix: use real cursor instead of virtual cursor 2025-08-12 07:52:19 -05:00
GitHub Action e970214be9 ignore: update download stats 2025-08-12 2025-08-12 12:04:42 +00:00
Camden Clark d4d4cf2c3a fix: preserve process.env when spawning formatter commands (#1850) 2025-08-12 02:05:26 -04:00
Dax 74562df0d1 Update guidelines-check.yml 2025-08-12 00:34:34 -04:00
Dax 54dd8104cc Update duplicate-issues.yml 2025-08-12 00:34:16 -04:00
Dax Raad b55774835d ci: add guidelines check workflow for PRs 2025-08-12 00:01:59 -04:00
Dax Raad dd2702ff9f ci: tweak 2025-08-11 23:52:16 -04:00
Dax Raad 9cbb201a28 ci: add duplicate issue detection workflow 2025-08-11 23:51:08 -04:00
Dax Raad d571fb08a7 support wildcard matching tool names in config 2025-08-11 23:37:09 -04:00
opencode 0cbb554365 release: v0.4.26 2025-08-12 03:25:36 +00:00
Dax Raad cdec3de6d3 fix azure reasoningEffort 2025-08-11 23:20:19 -04:00
Dax Raad 66d59549ac azure reasoning effort 2025-08-11 23:04:32 -04:00
opencode 9e351017db release: v0.4.25 2025-08-12 02:51:32 +00:00
Dax Raad b1cd71e65c Simplify git-committer agent definition for better maintainability 2025-08-11 22:45:40 -04:00
Dax Raad 5dbf5090dc refactor: replace OPENCODE_AGENTS env var with HTTP API call
Replace environment variable passing of agent data from Node.js to TUI
with proper HTTP API call to /agent endpoint. This improves architecture
by eliminating env var dependencies and allows dynamic agent data fetching.
2025-08-11 22:42:25 -04:00
opencode c536828dbe release: v0.4.24 2025-08-12 02:33:35 +00:00
Dax Raad 3b861c16ba fix pyright 2025-08-11 22:27:24 -04:00
opencode b95dcbb731 release: v0.4.23 2025-08-12 02:04:53 +00:00
Dax Raad 49c18fdbdd fix undo/redo when opencode is run in nested folders 2025-08-11 21:59:12 -04:00
Dax Raad c2a1da1b13 ignore: log 2025-08-11 21:52:05 -04:00
Dax Raad 952293b75a switch back to didUpdate instead of closing and opening file 2025-08-11 21:36:05 -04:00
opencode 0fc6637856 release: v0.4.22 2025-08-12 01:07:27 +00:00
Dax Raad 91a7b503d0 update anthropic prompt and variables 2025-08-11 21:01:33 -04:00
opencode e8bf1ff5ce release: v0.4.21 2025-08-12 00:30:49 +00:00
adamdotdevin 798d4269af feat: add clangd for cpp 2025-08-11 19:21:59 -05:00
adamdotdevin 6fb86ab3d1 fix: complete item on space 2025-08-11 18:58:42 -05:00
Carl Brugger a559cd5308 Fix plugin file name (#1837) 2025-08-11 23:43:43 +00:00
opencode 2754212a1a release: v0.4.20 2025-08-11 23:43:43 +00:00
adamdotdevin edfae413ca Revert "feat: improve file attachment pasting (#1704)"
This reverts commit 1127a5df43.
2025-08-11 18:37:34 -05:00
Jay V 497b5cbb36 ignore: share page thinking blocks 2025-08-11 19:36:34 -04:00
Aiden Cline 3dcfcfdebb feat: add -c and -s args to tui command following run command pattern (#1835) 2025-08-11 18:32:09 -05:00
Dax Raad 5ec4233910 ignore: fix share page 2025-08-11 16:12:26 -04:00
adamdotdevin 0b73c23c7c fix: collapsed tool calls hidden at times 2025-08-11 13:54:58 -05:00
Aiden Cline cc738eef30 docs: fix instructions (#1827) 2025-08-11 13:44:12 -05:00
Dax Raad 44d46e19a6 ignore: test 2025-08-11 14:43:42 -04:00
adamdotdevin 8d39f22200 fix: take up less vertical space 2025-08-11 13:38:39 -05:00
Dax Raad c71917db94 remove git bash tool coauthor message 2025-08-11 18:36:06 +00:00
opencode 96867e69bf release: v0.4.19 2025-08-11 18:36:06 +00:00
Dax Raad 5d25603044 Update GPT-5 system prompt to use copilot-specific prompt instead of codex prompt
🤖 Generated with [opencode](https://opencode.ai)

Co-Authored-By: opencode <noreply@opencode.ai>
2025-08-11 14:28:49 -04:00
Jay V 830f931ae2 docs: share 2025-08-11 14:19:22 -04:00
Jay V bc917ceb9b docs: share page 2025-08-11 14:01:20 -04:00
Jay V 264d21f3d9 docs: share page 2025-08-11 13:57:41 -04:00
Jay V a688de6348 docs: test share 2025-08-11 13:45:55 -04:00
Jay V 723ab1edb0 docs: test share 2025-08-11 13:38:03 -04:00
Jay V eef25c887e docs: comment out thinking blocks for share page 2025-08-11 13:21:59 -04:00
adamdotdevin 0e6cc67ee9 feat: toggle tool details visible 2025-08-11 11:58:46 -05:00
adamdotdevin 32eaf4076c fix: don't display placeholder on error 2025-08-11 11:58:46 -05:00
Jay V 582efe135a docs: share page fix 2025-08-11 12:51:19 -04:00
Jay V cb0e714100 docs: edits 2025-08-11 12:41:13 -04:00
opencode 2c845a0703 release: v0.4.18 2025-08-11 16:04:07 +00:00
adamdotdevin 4e44e6d270 fix: assistant message footer styles 2025-08-11 10:57:18 -05:00
adamdotdevin 224cabd720 fix: assistant message footer styles 2025-08-11 10:52:49 -05:00
adamdotdevin 04b03e8a4e fix: assistant message footer styles 2025-08-11 10:50:00 -05:00
opencode ce348e88e7 release: v0.4.17 2025-08-11 15:15:24 +00:00
Dax Raad d3425b976f fix azure gpt config 2025-08-11 10:56:16 -04:00
Dax Raad d85e4fee1d make models key optional in config 2025-08-11 10:54:14 -04:00
adamdotdevin 85c33cc5e8 fix: reformat assistant message footer 2025-08-11 09:38:52 -05:00
adamdotdevin 7e72ae534b feat: placeholder on pending assistant message 2025-08-11 09:29:44 -05:00
adamdotdevin d1cbf1d9ae fix: re-render messages on session error 2025-08-11 09:19:45 -05:00
spoons-and-mirrors 437ae99bd4 Fix: Respect agent's preferred model at TUI startup (#1683)
Co-authored-by: opencode <noreply@opencode.ai>
2025-08-11 08:51:35 -05:00
spoons-and-mirrors 1c8ea078db Feat: Implement Wrap-Around Navigation for List Selection (for Models and Tools modal) (#1768) 2025-08-11 08:47:51 -05:00
Timo Clasen 01f8eec4bf fix: only load the first local and global rule file (#1761) 2025-08-11 08:28:03 -05:00
Aiden Cline 8e8aed40af fix: instructions should be able to handle absolute paths (#1762) 2025-08-11 08:23:41 -05:00
opencode ff71080228 release: v0.4.16 2025-08-11 12:59:20 +00:00
Dax Raad eaaac1c4b3 ci: tweak 2025-08-11 08:54:14 -04:00
opencode a26844e375 release: v0.4.15 2025-08-11 12:49:52 +00:00
GitHub Action fc87d5afdb ignore: update download stats 2025-08-11 2025-08-11 12:04:33 +00:00
spoons-and-mirrors c41ca1f535 Feat: Add F2 Keybind to Cycle Through the 5 Most Recent Models (#1778) 2025-08-11 07:00:32 -05:00
cvzakharchenko 00ffe89f8e Issue 1676: Don't eat up the last newline in a multi-line replacement (#1777) 2025-08-11 06:55:45 -05:00
Jake ac1d8c3f9f Add support for biome.jsonc config file (#1791) 2025-08-11 06:48:46 -05:00
spoons-and-mirrors 219756c3d3 Fix: Sanitize MCP Tool Names for Consistency in User Expectations (#1769) 2025-08-11 01:59:50 -04:00
Stibbs f9d201daa5 chore: add OPENCODE env var (#1780) 2025-08-11 01:56:42 -04:00
Aiden Cline 21df5bbd20 feat (tui): agents dialog (#1802) 2025-08-11 01:46:38 -04:00
Dax Raad fce733492d fix run command to be less messy 2025-08-11 01:45:05 -04:00
opencode 714820eb3f release: v0.4.12 2025-08-11 05:28:22 +00:00
Dax Raad 1cc168f826 show combined output of bash tool progressively 2025-08-11 01:23:00 -04:00
Dax Raad 633d575a48 fix plan mode bash tool making changes 2025-08-11 01:15:12 -04:00
opencode d6a62d7fe0 release: v0.4.11 2025-08-11 02:30:21 +00:00
Dax Raad e71b965087 ci: tweaks 2025-08-10 22:23:59 -04:00
Aiden Cline 81ecb86a40 fix: enforce field requirement for cli cmds (#1796) 2025-08-10 22:17:12 -04:00
opencode 4633e7e2bb release: v0.4.6 2025-08-11 01:59:27 +00:00
Dax Raad b86b24bca2 add OPENCODE_DISABLE_AUTOUPDATE flag 2025-08-10 21:52:52 -04:00
Dax Raad 87be61f561 docs: docs agent 2025-08-10 21:40:49 -04:00
Dax Raad 45b22d0581 ci: smoke test 2025-08-10 21:37:48 -04:00
Dax Raad 2c8bd78883 pass through additional agent options to the provider 2025-08-10 21:34:46 -04:00
Tom 489e54b04b fix(plugin): prevent compiled binary hang by removing lazy dynamic import (#1794)
Co-authored-by: opencode <noreply@opencode.ai>
2025-08-10 21:31:15 -04:00
opencode 4e87c698ce release: v0.4.3 2025-08-11 00:53:06 +00:00
Dax Raad 828bc3b72f switch gpt-5 to codex prompt 2025-08-10 20:47:38 -04:00
Dax Raad 652bed02bb support agent options 2025-08-10 20:30:37 -04:00
adamdotdevin 80347b1ad4 feat: thinking blocks rendered in tui and share page 2025-08-10 19:25:03 -05:00
Frank bc0c1735e1 wip gateway 2025-08-10 12:30:52 -04:00
Aiden Cline bb5396263c feat: webfetch permission support (#1772) 2025-08-10 08:00:44 -05:00
GitHub Action 000290ce17 ignore: update download stats 2025-08-10 2025-08-10 12:04:14 +00:00
Frank 3630f6ae3f wip: gateway 2025-08-10 01:17:48 -04:00
Frank 45d4395a54 wip: gateway 2025-08-10 01:03:15 -04:00
Frank 86b91c6979 wip: gateway 2025-08-10 00:29:00 -04:00
spoons-and-mirrors a593e45195 Feat: Add Agent Name in the LLM Response Footer (and re-order it) (#1770) 2025-08-09 20:22:16 -05:00
Frank 56685e4cc2 Update moonshot ai provider doc 2025-08-09 19:22:50 -04:00
Dax Raad b5798d2dae use minimal reasoning effort for gpt-5 2025-08-09 15:38:48 -04:00
Aiden Cline d88272d466 feat: eslint lsp (#1744) 2025-08-09 11:04:58 -05:00
Aiden Cline 232e96c4db better permissions ux when denying (#1747) 2025-08-09 11:03:33 -05:00
GitHub Action 64cfd3c1d5 ignore: update download stats 2025-08-09 2025-08-09 12:04:16 +00:00
Frank d3511e33ce wip gateway 2025-08-09 01:28:27 -04:00
Dominik Engelhardt 1127a5df43 feat: improve file attachment pasting (#1704) 2025-08-08 20:06:38 -05:00
Dax Raad 706b7b1481 remove synthetic message in plan mode, fixes being confused in build mode 2025-08-08 20:45:24 -04:00
Dax Raad e530a3287a gpt-5 lower verbosity 2025-08-08 20:42:22 -04:00
Dax 9c7361c901 Remove unused OpenTelemetry tracing and fix overlapping highlights (#1738)
Co-authored-by: opencode <noreply@opencode.ai>
2025-08-08 20:20:01 -04:00
Erick Christian ac1b1ad797 feat(agent): allow mode selection during creation (#1699) 2025-08-08 20:07:20 -04:00
Clayton 60115f0458 Reference the actual name of the windows package (#1700) 2025-08-08 20:07:00 -04:00
zWing 2ec6cc8fbe chore(js-sdk): Compatible with nodenext (#1667) 2025-08-08 20:05:50 -04:00
rmoriz 8a4bd7d619 Clarify remote mcp error (#1729)
Co-authored-by: opencode <noreply@opencode.ai>
2025-08-08 20:04:26 -04:00
gsbain 4d77ccc8f9 Docs: Homebrew can install Opencode on Linux (#1737) 2025-08-08 20:04:02 -04:00
Frank 8045ce5633 fix deploy 2025-08-08 18:39:47 -04:00
Frank 2590813353 fix deploy script 2025-08-08 17:59:21 -04:00
Max Pod add5b640d5 docs: Update plugins.mdx (#1690) 2025-08-08 17:11:06 -04:00
Typing Turtle eeda47c87f docs: Adds required models field to variables documentation (#1709) 2025-08-08 16:57:31 -04:00
Yihui Khuu 45d7b7b28e fix(tui): preserve scroll position when reflowing due to message stream (#1716) 2025-08-08 13:14:09 -05:00
Frank 02d9d9c991 wip: gateway 2025-08-08 13:24:50 -04:00
Frank 3be6d94a02 wip: gateway 2025-08-08 13:24:32 -04:00
GitHub Action 7939402232 ignore: update download stats 2025-08-08 2025-08-08 12:04:40 +00:00
Timo Clasen d089f906a2 fix(TUI): enable general (sub-) agent for @ referencing (#1705) 2025-08-08 05:36:55 -05:00
opencode 2e1d7c85c7 release: v0.4.1 2025-08-08 03:01:03 +00:00
Dax Raad 56587b1849 temporary fix for max output token 2025-08-07 22:54:59 -04:00
Dax Raad 3bd7d33132 docs: fix 2025-08-07 21:49:18 -04:00
Dax Raad d408886e43 renable todo tool 2025-08-07 21:47:37 -04:00
Dax Raad e46ecf67d9 looser todo tool schema 2025-08-07 21:47:37 -04:00
Jay V 60452a4d73 docs: update cli 2025-08-07 19:24:08 -04:00
Jay V 66023f4402 docs: edit agent doc 2025-08-07 18:51:54 -04:00
Dax Raad 83fb7dfbb6 docs: remove modes from sidebar navigation
🤖 Generated with [opencode](https://opencode.ai)

Co-Authored-By: opencode <noreply@opencode.ai>
2025-08-07 16:35:35 -04:00
Dax 77c101d742 Merge agent and mode into one (#1689)
The concept of mode has been deprecated, there is now only the agent field in the config.

An agent can be cycled through as your primary agent with <tab> or you can spawn a subagent by @ mentioning it. if you include a description of when to use it, the primary agent will try to automatically use it

Full docs here: https://opencode.ai/docs/agents/
2025-08-07 16:32:12 -04:00
Jay V 62bff76d3a docs: slash commands 2025-08-07 16:16:16 -04:00
Timo Clasen 134a698437 fix: get session api (#1684) 2025-08-07 15:28:18 -04:00
Aiden Cline 12ab0c9048 fix: modal pastes (#1677) 2025-08-07 13:23:58 -05:00
GitHub Action 763a37f880 ignore: update download stats 2025-08-07 2025-08-07 12:04:29 +00:00
Aiden Cline 3913566e28 fix: text selection bug (#1664) 2025-08-07 05:32:34 -05:00
opencode 8a68dfdcbf release: v0.3.133 2025-08-07 00:30:05 +00:00
Dax Raad 4bd6efe2a9 add api to get session 2025-08-06 20:24:36 -04:00
Jay V 99ec88287b docs: config doc edits 2025-08-06 16:10:17 -04:00
Jay V 0d239dbe88 docs: typos 2025-08-06 15:45:16 -04:00
Timo Clasen 8f65d92165 fix(docs): small_model is not used for summarization (#1360) 2025-08-06 14:03:14 -05:00
Aiden Cline 77a4ffd7e0 fix: interface conversion panic (#1655) 2025-08-06 14:02:33 -05:00
Jay V 65ff65a5e7 docs: add undo to tutorial 2025-08-06 13:51:47 -04:00
Dax Raad 92c79f40b5 ignore: remove demo plugin 2025-08-06 11:36:53 -04:00
Dax Raad ed3d49d74a add snapshot field in config to disable snapshots 2025-08-06 11:35:37 -04:00
Aiden Cline 2019b160b6 docs: update readme (#1654) 2025-08-06 09:35:02 -05:00
Aiden Cline 0590e57765 chore: update marked-shiki, remove patch (#1653) 2025-08-06 08:47:53 -05:00
GitHub Action c0e62ad88d ignore: update download stats 2025-08-06 2025-08-06 12:04:53 +00:00
Yihui Khuu 7ba89b3d85 fix: run command should use specified model from cli args if provided (#1648) 2025-08-06 05:39:44 -05:00
Aiden Cline 41943011c0 docs: document permissions (#1638) 2025-08-06 05:18:08 -05:00
Aiden Cline a1a434a627 fix: highlight after text wrap (#1640) 2025-08-06 05:17:35 -05:00
Aiden Cline 947bf020a4 fix: handle undefined agent in task tool (#1642) 2025-08-06 05:16:43 -05:00
Aiden Cline 4fa81b899d permissions disallow support (#1627) 2025-08-05 19:14:28 -05:00
adamdotdevin a05e74f539 feat: better assistant message visual 2025-08-05 19:05:44 -05:00
Jay V 72bd8ab912 docs: identity 2025-08-05 19:36:10 -04:00
Timo Clasen 27c6625dd6 docs(plugins): fix typo (#1621) 2025-08-05 17:16:47 -05:00
Aiden Cline 2319c08054 fix: markdown table renders (#1623) 2025-08-05 17:16:35 -05:00
Timo Clasen 97677d8f05 fix: prevent title regeneration on auto compact (#1628) 2025-08-05 17:15:50 -05:00
Dax Raad 7ec57f1fd9 hint back to llm when tool does not exist 2025-08-05 15:58:12 -04:00
Jay V ecef453e51 docs: edit 2025-08-05 12:55:57 -04:00
adamdotdevin ef1f836f01 chore: cleanup old sdk 2025-08-05 11:46:12 -05:00
Dax Raad 5e9bf32f82 ci: send stats to posthog 2025-08-05 12:01:48 -04:00
GitHub Action 0d76317631 ignore: update download stats 2025-08-05 2025-08-05 12:04:48 +00:00
Yihui Khuu 6598713d0e fix: allow disabling the default general agent (#1616) 2025-08-05 05:20:00 -05:00
Omar Shaarawi 771f7bbf41 validate file part bounds to prevent panic (#1612) 2025-08-05 05:18:50 -05:00
Aiden Cline 4dd304caed docs: make formatter docs a bit more clear (#1613) 2025-08-05 05:17:56 -05:00
Aiden Cline 29f1bd9ead fix: server.root is not a function (#1614) 2025-08-05 05:17:32 -05:00
Timo Clasen 35865c50c5 fix(plugins): improve session idle event (#1615) 2025-08-05 05:16:43 -05:00
opencode 126b82c65b release: v0.3.130 2025-08-05 03:25:28 +00:00
Dax Raad 1fbfb6435a re-export shell $ for plugin 2025-08-04 23:20:04 -04:00
opencode 5918e5dcb2 release: v0.3.129 2025-08-05 01:18:50 +00:00
Dax Raad a147526677 fix @opencode-ai/plugin exports 2025-08-04 21:12:18 -04:00
Frank 51ac18cf4a sync 2025-08-04 21:09:44 -04:00
Frank facf209885 wip: gateway 2025-08-04 21:08:29 -04:00
Jay V c093eeb759 docs: lock 2025-08-04 19:53:50 -04:00
Jay V 14d3a9893f docs: edit new docs 2025-08-04 19:52:03 -04:00
Mahamed-Belkheir 93575f4a51 fix: default value for models with no cost object (#1601) 2025-08-04 16:45:35 -05:00
Min Chun Fu 7acd4fa85d added vesper theme (#1602) 2025-08-04 16:45:00 -05:00
Aiden Cline 5f154b69d8 docs: make plugins page exposed (#1603) 2025-08-04 16:44:28 -05:00
opencode c3bc30a155 release: v0.3.128 2025-08-04 16:20:39 +00:00
Dax Raad eca7b8fd11 hack to return tool call errors back to model 2025-08-04 12:15:24 -04:00
opencode 927e6f121a release: v0.3.127 2025-08-04 16:06:13 +00:00
GitHub Action a2962a4f65 ignore: update download stats 2025-08-04 2025-08-04 12:04:34 +00:00
Aiden Cline 29bc4c07ae fix double help printing (#1580) 2025-08-04 05:03:27 -05:00
Frank cd7af235a2 fix docs 2025-08-04 00:23:02 -04:00
Dax Raad 48faf9d3ce wip: plugins 2025-08-03 21:43:58 -04:00
Dax Raad 4fc04bbac2 wip: plugin load from package 2025-08-03 21:19:03 -04:00
Dax Raad 759e948e2b Add workflow_dispatch trigger to typecheck workflow 2025-08-03 17:16:20 -04:00
Aiden Cline 3f55f62607 fix: patch marked-shiki (#1569) 2025-08-03 16:13:35 -05:00
Dax Raad 624a7d038a Add typecheck workflow 2025-08-03 17:12:23 -04:00
Dax Raad fa03e06c2d ignore: cleanup 2025-08-03 17:09:30 -04:00
Yordis Prieto ab3d6c9797 chore: add ts-expected-error (#1575) 2025-08-03 17:09:19 -04:00
Yordis Prieto ff427fd1fe chore: remove unnecessary TypeScript error suppression (#1571) 2025-08-03 15:50:08 -04:00
opencode 2db4143286 release: v0.3.126 2025-08-03 19:45:14 +00:00
Dax Raad 75f7fa8cf4 ci: ignore 2025-08-03 15:39:34 -04:00
Dax Raad 4693b55dba ci: ignore 2025-08-03 15:38:39 -04:00
Dax Raad d5dacdb63c fix bash tool not showing stderr 2025-08-03 15:34:52 -04:00
Aiden Cline bf1699617f tweak: filter out duplicate instructions (#1567) 2025-08-03 15:10:21 -04:00
Dax Raad e3781104c4 increase models.dev polling interval to hourly 2025-08-03 14:58:35 -04:00
Aiden Cline 24d063b7ae docs: fix mixed up documentation (#1564) 2025-08-03 13:01:09 -05:00
Dax Raad 2cadf5a093 fix bash tool getting stuck on interactive commands 2025-08-03 13:52:50 -04:00
opencode 3cfddc7a09 release: v0.3.123 2025-08-03 17:13:33 +00:00
Dax Raad 878c7ed67e ci: ignore 2025-08-03 13:12:35 -04:00
opencode 48188bf294 release: v0.3.122 2025-08-03 16:19:09 +00:00
Dax Raad 614501c1a2 more efficient snapshots in parallel toolcalls 2025-08-03 12:12:28 -04:00
Giuseppe Rota 09aa285ae5 fix(docs): move disabled providers paragraph to its proper section (#1547) 2025-08-03 11:28:57 -04:00
Dax Raad b926d0c010 more fixes for shell 128 error 2025-08-03 11:25:58 -04:00
opencode 9436c7f774 release: v0.3.120 2025-08-03 14:59:03 +00:00
Dax Raad 1eca9531ea ci: ignore 2025-08-03 10:52:35 -04:00
Dax Raad 1fc92d91c0 ci: ignore 2025-08-03 10:42:52 -04:00
Dax Raad dfcff892a1 fix shell error 128 2025-08-03 10:30:23 -04:00
GitHub Action 2d68127b07 ignore: update download stats 2025-08-03 2025-08-03 12:04:04 +00:00
Aiden Cline e159922c06 fix: expand tilde for file: references (#1553) 2025-08-03 06:15:06 -05:00
Dax Raad 298a444df0 ci: ignore 2025-08-03 03:54:17 -04:00
Dax Raad 7079098206 ci: bun cache 2025-08-03 03:53:31 -04:00
Dax Raad e73e51597d ci: ignore 2025-08-03 03:45:05 -04:00
Dax Raad 461e5469e9 ci: ignore 2025-08-03 03:37:53 -04:00
Dax Raad 54f81220df ci: ignore 2025-08-03 03:35:17 -04:00
The Pangolier acd601220a Share link hotfix (#1513) 2025-08-03 03:02:24 -04:00
Yordis Prieto 0c86e73e95 remove: delete extension test file (#1554) 2025-08-03 02:58:10 -04:00
Frank 2cad480fed sync 2025-08-02 21:28:03 -04:00
Frank 77ab87abeb Add Zhipu AI provider 2025-08-02 21:20:44 -04:00
Dax Raad 765c149bba ci: ignore 2025-08-02 18:56:34 -04:00
Dax Raad d3ca086b59 wip: plugins 2025-08-02 18:50:19 -04:00
Aiden Cline 62d67208e3 tweak: make gh action ignore url mentions of opencode (#1531) 2025-08-02 09:31:23 -05:00
Dominik Engelhardt 6b58ab0b47 Choose model according to the docs (#1536) 2025-08-02 09:29:03 -05:00
Yihui Khuu 128bafa095 fix(tui): attachment highlighting issues in messages (#1534) 2025-08-02 09:26:44 -05:00
Yihui Khuu 680e611a10 fix(tui): attachment source is not stored when using message from message history (#1542) 2025-08-02 09:23:32 -05:00
Aiden Cline 587ab4f16a ignore: fix dev branch (#1529) 2025-08-02 09:11:38 -05:00
GitHub Action e2636b39e4 ignore: update download stats 2025-08-02 2025-08-02 12:04:12 +00:00
Ricardo Gonzalez 55a73b3e2e feat(models): enable Kimi k2 ⇄ Claude trajectory handoff (#1525) 2025-08-01 23:05:06 -04:00
Aiden Cline eebd7ed5ff fix: include stderr in bash tool output (#1511) 2025-08-01 19:20:32 -05:00
Aiden Cline 63a7f04f65 better configuration error messages (#1517) 2025-08-01 19:10:32 -04:00
Jay V 766d7b9f7d docs: cerebras 2025-08-01 18:30:29 -04:00
opencode 508734438b release: v0.3.112 2025-08-01 21:53:33 +00:00
Dax Raad f75fc5af22 force models.dev refresh on auth login 2025-08-01 17:48:01 -04:00
Dax Raad cbd7db5a73 make top_p configurable 2025-08-01 17:03:33 -04:00
Dax Raad 36318f74f7 configurable lsp 2025-08-01 14:52:10 -04:00
Brinsil Elias 4bacee2db6 fix(docs): Fix formatting for Node.js installation section (#1497) 2025-08-01 14:15:38 -04:00
CodinCat e20ab5b7ee handle the optional v in upgrade command when using curl (#1500) 2025-08-01 14:15:22 -04:00
Yordis Prieto 12172203d7 chore: enhance bash command tests with config mock and timeout adjustments (#1486)
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
2025-08-01 14:14:54 -04:00
Dax Raad b6fcc7047f allow search in provider select 2025-08-01 14:03:22 -04:00
Dax Raad feb43e8550 add version to user-agent 2025-08-01 12:18:09 -04:00
adamdotdevin 5aa811a6c5 fix: unshare command missing 2025-08-01 09:30:42 -05:00
Aiden Cline 2c61674f83 tweak: sanitize mcp server names (#831) 2025-08-01 09:11:40 -05:00
Aiden Cline b9c143096b fix: bash tool errors for chmod (#1502) 2025-08-01 09:10:09 -05:00
Aiden Cline 45d835e5e8 fix: {file:...} references weren't being parsed correctly in some cases (#1499) 2025-08-01 08:39:21 -05:00
adamdotdevin ce317ff90f ignore: include usage in local setup 2025-08-01 07:42:36 -05:00
GitHub Action 892ba79c44 ignore: update download stats 2025-08-01 2025-08-01 12:04:33 +00:00
adamdotdevin 3729f2647a chore: add local qwen3 to config 2025-08-01 06:27:08 -05:00
Timo Clasen 427cc1df23 docs(permissions): add wildcard example (#1494) 2025-08-01 05:24:32 -05:00
Dax Raad c64cd54d5d poll for models.dev changes 2025-07-31 23:47:42 -04:00
Dax Raad d944eed4d5 add user agent for models.dev request 2025-07-31 22:00:45 -04:00
Dax Raad 56f41c11a8 do not mark errored tool calls as aborted 2025-07-31 21:45:40 -04:00
Dax Raad 88842a633e better guarding against bash commands that go outside of cwd 2025-07-31 21:42:30 -04:00
Frank 3e19c2dc6c Update STATS.md 2025-07-31 21:42:05 -04:00
Dax Raad f4254751e6 improve wildcard matching for permissions 2025-07-31 20:40:05 -04:00
Dax Raad ebdc891c88 ci: ignore release commits 2025-07-31 19:57:07 -04:00
Dax Raad 0ae036bf22 fix escape button not canceling if retry in progress 2025-07-31 19:55:57 -04:00
Dax Raad 8294606576 docs: sync 2025-07-31 19:50:51 -04:00
Dax Raad a383f1a833 docs: formatters 2025-07-31 19:50:31 -04:00
Dax Raad 9da86a35cf ignore: config 2025-07-31 19:45:44 -04:00
opencode c2eee24590 Release v0.3.105 2025-07-31 23:41:27 +00:00
Dax Raad 918b7019c7 formatter config 2025-07-31 19:36:07 -04:00
Jay V adeb89b964 docs: edit premissions doc 2025-07-31 19:10:54 -04:00
opencode 8af1310831 Release v0.3.104 2025-07-31 23:02:36 +00:00
Dax Raad a64165b456 allow disabling formatter 2025-07-31 18:56:04 -04:00
Dax Raad 4c849f6a63 fix issue with some bash commands asking for permission 2025-07-31 18:35:51 -04:00
Dax Raad cea323b743 ignore: update opencode.json 2025-07-31 18:13:40 -04:00
Dax Raad 9b931f0498 docs: permissions 2025-07-31 18:11:34 -04:00
Dax Raad 69cb5756c0 docs: permissions 2025-07-31 18:11:34 -04:00
Frank 7391d0ff61 Remove hardcoded vscode extension theme
publish-vscode / publish (push) Waiting to run
2025-07-31 17:53:18 -04:00
Jay V fd8287705c docs: add more providers 2025-07-31 17:47:24 -04:00
opencode dfe1deeb67 Release v0.3.102 2025-07-31 21:25:12 +00:00
Dax Raad 82c0dcc62d wip: permissions 2025-07-31 17:19:56 -04:00
Dax Raad c6a7ab6bd6 ignore: ts optimization 2025-07-31 16:54:15 -04:00
Dax Raad 701cd937a8 wip: permissions 2025-07-31 16:51:55 -04:00
Dax Raad f1e0e40868 wip: permissions 2025-07-31 16:38:37 -04:00
Aiden Cline 8788e221b8 fix: load global jsonc (#1479) 2025-07-31 15:02:28 -05:00
Aiden Cline 1d56302bb5 fix: session ordering (#1474) 2025-07-31 14:17:47 -05:00
Frank 85605f8d88 Add provider instruction for Azure OpenAI 2025-07-31 14:37:26 -04:00
Jay V f1c12a7257 docs: edit providers doc 2025-07-31 14:11:40 -04:00
opencode-agent[bot] 77e6d78d91 docs: Enhanced providers docs with troubleshooting (#1441)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: jayair <jayair@users.noreply.github.com>
2025-07-31 13:08:12 -04:00
adamdotdevin b18a96eb67 fix: permission state hangs 2025-07-31 11:36:08 -05:00
Dax Raad ca454c91ca wip: refactor permissions 2025-07-31 12:26:47 -04:00
adamdotdevin 22c1112903 feat: more scriptable tui (api) 2025-07-31 11:24:23 -05:00
neolooong 1d503b1536 fix(editor): handle UTF-8 characters properly in SetValueWithAttachments (#1469) 2025-07-31 10:45:43 -05:00
adamdotdevin 2f1302e1a2 fix: missing operationId 2025-07-31 10:19:42 -05:00
adamdotdevin 3c8930192f fix: test 2025-07-31 10:10:34 -05:00
adamdotdevin 1606b52fd7 fix: optional toolCallID 2025-07-31 10:09:44 -05:00
adamdotdevin a0f82ecef8 fix: test 2025-07-31 10:07:58 -05:00
adamdotdevin 9f429d8dd9 wip: tui permissions 2025-07-31 09:59:17 -05:00
opencode 6aa555c492 Release v0.3.101 2025-07-31 14:23:13 +00:00
Dax Raad 0501054320 ci: tweak 2025-07-31 10:09:43 -04:00
Dax Raad 82505c3582 ci: fix 2025-07-31 09:46:36 -04:00
Dax Raad 5382dc70cb ci: tweak 2025-07-31 09:39:44 -04:00
Dax Raad f85635f8dd ci: tweak 2025-07-31 09:35:57 -04:00
Dax Raad bc4274315c ci: reorder 2025-07-31 09:29:55 -04:00
GitHub Action 878a126d22 ignore: update download stats 2025-07-31 2025-07-31 12:04:25 +00:00
Aiden Cline d60e346cbb feat: jsonc configuration file support (#1434) 2025-07-31 06:25:26 -05:00
Aiden Cline 3f8f517081 fix: process revert cleanup before creating new messages (#1448) 2025-07-31 05:07:59 -05:00
Dax Raad d2b67b67dd ci: stainless 2025-07-31 01:42:52 -04:00
Dax Raad 31c6306a7d ci: tweak 2025-07-31 01:35:11 -04:00
Dax Raad ea409b3874 ci: tweak 2025-07-31 01:33:21 -04:00
Dax Raad e7aa83fa8e ci: scripts 2025-07-31 01:25:24 -04:00
Dax Raad 617e80c14f ci tweaks 2025-07-31 01:20:12 -04:00
Dax df4a6a74cd ci: new publish method (#1451) 2025-07-31 01:05:35 -04:00
Dax 083682c6a8 ci: new publish method (#1451) 2025-07-31 01:00:29 -04:00
Simon Westlin Green b67c367a40 Use responses API for Azure (#1428)
publish / publish (push) Waiting to run
2025-07-30 23:22:59 -04:00
Robert Holden 1167e12f72 feat: mode directory markdown configuration loading (#1377) 2025-07-30 23:22:43 -04:00
Josh 30e5d32ed8 Add http-referer header for vercel ai gateway requests (#1403) 2025-07-30 23:22:24 -04:00
Yordis Prieto afb3edd234 docs: clarify Bun's default registry resolution in index.ts (#1438) 2025-07-30 23:21:07 -04:00
CodinCat 8f8bd188dd fix typo in bash.ts (#1444) 2025-07-30 23:20:48 -04:00
Dax 50c93a349f use treesitter to parse bash commands and catch commands that go outside of cwd (#1443) 2025-07-30 20:57:52 -04:00
Jay V 2f51f9d88d docs: edit 2025-07-30 19:11:36 -04:00
Jay V dcb54d465b docs: add new providers doc, reorg sidebar, edits 2025-07-30 18:16:11 -04:00
Yordis Prieto f74cd37818 fix: update glob pattern and path in tool test (#1436) 2025-07-30 15:42:13 -05:00
Yordis Prieto f2bac1532b fix: unit test assertion (#1435)
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
2025-07-30 15:13:37 -05:00
Dax Raad f181fbf3f0 lower max retries to 3 - ai sdk currently cannot abort during a retry delay so things appear to be frozen
publish / publish (push) Waiting to run
2025-07-30 15:08:25 -04:00
Dax Raad 4a53957e9d release undo/redo 2025-07-30 13:09:18 -04:00
Aiden Cline a33870ea66 fix: attachment highlighting (#1427) 2025-07-30 11:43:34 -05:00
Aiden Cline d4e91d3d5f fix: prevent read tool from opening binary files and corrupting session (#1425) 2025-07-30 11:00:23 -05:00
GitHub Action 66891b148b ignore: update download stats 2025-07-30 2025-07-30 12:04:23 +00:00
Sam Huckaby 3bd652b22e fix: quick grammar and spelling check (#1402) 2025-07-30 05:54:47 -05:00
Aiden Cline 02d838c68e tweak: adjust astro css to render mixed nested lists (#1411) 2025-07-30 05:51:52 -05:00
municorn 8618f0d88b build: add @octokit/rest to opencode dependencies (#1396)
Co-authored-by: Frank <frank@sst.dev>
2025-07-29 22:33:25 -04:00
Dax Raad e9af4d7216 update beast prompt for openai models
publish / publish (push) Waiting to run
2025-07-29 22:15:13 -04:00
Dax Raad 8528f471c7 experimental well-known auth support
publish / publish (push) Waiting to run
2025-07-29 19:30:51 -04:00
Yordis Prieto 9790340493 chore: fix test to have deterministic testing (#1401) 2025-07-29 17:54:22 -05:00
Dax Raad c9b9c844db remove min/max in tool schemas
publish / publish (push) Waiting to run
2025-07-29 17:39:47 -04:00
Frank f30b5c0ec4 convert share backend to hono app 2025-07-29 16:39:48 -04:00
adamdotdevin c3685d1efe feat: show git diff in reverted messages 2025-07-29 13:11:38 -05:00
Yordis Prieto f294293e2f fix: update file name extraction in uploads test to use __filename (#1395) 2025-07-29 12:28:44 -05:00
Yordis Prieto 83ebda87d2 fix: improve handling of global File object in uploads tests (#1394) 2025-07-29 11:30:39 -05:00
Yordis Prieto 1588863883 chore: fix null handling in multipartFormRequestOptions test (#1385) 2025-07-29 11:17:03 -05:00
Andrea Grandi 173da3caaf feat: show current git branch in status bar, and make it responsive (#1339)
Co-authored-by: adamdotdevin <2363879+adamdottv@users.noreply.github.com>
2025-07-29 11:15:04 -05:00
Dax Raad 5a98110ab0 strip todo tool instructions from non anthropic models 2025-07-29 11:56:53 -04:00
Jacob Hands 9e0edaa5d6 feat: add OPENCODE_CONFIG env var for specifying a custom config file (#1370) 2025-07-29 11:03:11 -04:00
GitHub Action 9e6f0de575 ignore: update download stats 2025-07-29 2025-07-29 12:04:40 +00:00
Aiden Cline d9278e4dcc fix: task type error (#1384) 2025-07-29 06:18:34 -05:00
Dax Raad 2160f0815c trim opencode title 2025-07-28 23:24:38 -04:00
Dax Raad 53ecda4ef1 wip: undo properly remove messages from UI 2025-07-28 22:58:31 -04:00
Dax Raad 4f62117758 wip: snapshot 2025-07-28 22:58:31 -04:00
Jay V 26335aeb01 docs: share page hide patch part 2025-07-28 20:04:00 -04:00
Jay V 1931d70e77 docs: adding 2025-07-28 20:00:30 -04:00
Jay V 3ae8e63ce5 Tweak auth cli copy 2025-07-28 20:00:30 -04:00
Dax Raad fa6fad2bac ignore: tweak
publish / publish (push) Waiting to run
2025-07-28 12:20:37 -04:00
Dax Raad ff611ae792 fix phantom tool call failed messages and empty text parts with some models 2025-07-28 12:19:38 -04:00
GitHub Action 90d8c47c95 ignore: update download stats 2025-07-28 2025-07-28 12:04:21 +00:00
Frank 2b9ab27a6f vscode: add cmd+shift+esc keybinding
publish-vscode / publish (push) Waiting to run
2025-07-27 15:54:45 -04:00
Frank 5a024afa87 vscode: bring oc terminal to front if already opened 2025-07-27 14:57:45 -04:00
Frank f56daab456 show opencode button in vscode when focused on terminal 2025-07-27 14:44:14 -04:00
Aiden Cline f9d45b7d3b fix: attachment bugs (#1335) 2025-07-27 12:21:31 -05:00
Frank adfcd1a9eb fix input format affected by installing vscode extension
publish / publish (push) Waiting to run
2025-07-27 11:56:18 -04:00
Frank ebc7c8dfd6 simplify github action 2025-07-27 09:56:09 -04:00
GitHub Action 487275dce8 ignore: update download stats 2025-07-27 2025-07-27 12:04:15 +00:00
Aiden Cline 377a66d415 docs: document small_model cfg option (#1347) 2025-07-26 16:56:38 -05:00
Dax Raad 1cd12ca740 ci: fix opencode github 2025-07-26 10:02:31 -04:00
Aiden Cline aa30428e76 fix: strip thinking blocks from title (#1325) 2025-07-26 08:29:04 -05:00
GitHub Action 2ff7883f78 ignore: update download stats 2025-07-26 2025-07-26 12:03:59 +00:00
Frank 6692d1c5dc wip: github actions
publish / publish (push) Waiting to run
2025-07-26 02:49:05 -04:00
Frank 6182b4a0c1 wip: github action 2025-07-26 01:03:23 -04:00
Frank 6b7cfde20a wip: github actions
publish / publish (push) Waiting to run
2025-07-25 20:27:42 -04:00
Didier Durand 03e9ee7293 fixing various typos in text. (#1185) 2025-07-25 20:20:01 -04:00
Dax Raad 4fc32f7c9a better mcp support - should fix hanging when streamable http server is added
publish / publish (push) Waiting to run
2025-07-25 19:19:47 -04:00
Frank 39e0ae70fe wip: github actions
publish / publish (push) Waiting to run
2025-07-25 19:05:55 -04:00
Frank a67106b700 wip: github action
publish-github-action / publish (push) Waiting to run
2025-07-25 18:33:45 -04:00
Dax Raad 5a3aed4e88 qwen optimizations it works good now 2025-07-25 18:31:08 -04:00
Frank a3bd92ee60 wip: github actions
publish-github-action / publish (push) Waiting to run
publish / publish (push) Waiting to run
2025-07-25 18:29:53 -04:00
Michael Hanson 7e3fe04b06 Fix a broken example in the MCP documentation and add more clarity (#1322) 2025-07-25 17:47:01 -04:00
Frank 35a914ad99 wip: github actions
publish / publish (push) Waiting to run
2025-07-25 17:34:47 -04:00
Dax Raad 01198a5fdc wip: sync
publish / publish (push) Waiting to run
2025-07-25 15:52:27 -04:00
Dax Raad a765b14ad5 wip: drop 2025-07-25 15:51:02 -04:00
Dax Raad 2767f4f9c3 handle uploaded text/plain 2025-07-25 15:48:42 -04:00
kehanzhang a155713a52 fix(headless): respect mode passed to /message endpoint (#1300) 2025-07-25 15:26:49 -04:00
Dax Raad d655601c47 docs: mode temperature 2025-07-25 13:45:04 -04:00
Dax Raad 4b94f390ce allow temperature to be configured per mode
publish / publish (push) Waiting to run
2025-07-25 13:29:44 -04:00
Dominik Engelhardt 8e036cf17b fix: apply content-level caching for non-anthropic providers (#1305) 2025-07-25 12:19:44 -04:00
Yihui Khuu 0254c612ee feat: add csharp lsp (#1312) 2025-07-25 12:17:06 -04:00
Dax Raad 5febb0ff94 fix issue with trailing whitespace error in assistant message 2025-07-25 10:56:16 -04:00
Dax Raad 79edca063e fix reading model from config
publish / publish (push) Waiting to run
2025-07-25 10:53:37 -04:00
Yihui Khuu 58c47c20a2 fix: header width to display header in one line when sharing disabled (#1310) 2025-07-25 09:32:06 -05:00
Dax Raad 4f6a568d80 fix double system prompt 2025-07-25 10:28:42 -04:00
Dax Raad 1823d20d26 disable todo tools by default in agent
publish / publish (push) Waiting to run
2025-07-25 10:23:23 -04:00
Dax Raad 4ecfa69a07 fix symlinked agents
publish / publish (push) Waiting to run
2025-07-25 10:20:16 -04:00
GitHub Action 34bdc43a7f ignore: update download stats 2025-07-25 2025-07-25 12:04:21 +00:00
Dax Raad 82e28e2717 agents better display when spawning
publish / publish (push) Waiting to run
2025-07-24 23:08:03 -04:00
Dax Raad 31febec1c5 docs: agents
publish / publish (push) Waiting to run
2025-07-24 22:18:49 -04:00
Dax Raad 149bfd5e36 docs: agents 2025-07-24 22:16:16 -04:00
Dax Raad 61dc0a7b3c docs: agents 2025-07-24 22:07:30 -04:00
Dax Raad 0de957a2f0 real life totally configurabl ai subasians
publish / publish (push) Waiting to run
2025-07-24 21:21:02 -04:00
Frank 0caf100598 wip: github actions 2025-07-24 19:03:10 -04:00
Jay V 9f51d713ce docs: add to quick start 2025-07-24 18:57:54 -04:00
Filip c903c82704 Fix: added environment() to summarize() (#1290) 2025-07-24 18:24:54 -04:00
Dax Raad 621e7f8697 wip: handle deleting file 2025-07-24 17:49:23 -04:00
Dax Raad 877cbfc45b wip: fix type errors 2025-07-24 17:38:11 -04:00
Dax Raad 0d12a8c4d9 wip: more snapshot stuff 2025-07-24 17:38:11 -04:00
Aiden Cline 0463894731 (tui) tweak: add setting for scroll speed (#1288) 2025-07-24 16:34:59 -05:00
Clay Warren 9b94c9c57f feat: Replace unzip with @zip.js/zip.js for Windows compatibility (#662) 2025-07-24 16:49:04 -04:00
Filip 0ef0b3404b fix: add custom() to system prompt on summarize (#1289) 2025-07-24 16:48:17 -04:00
Filip 771c714b10 fix: edit tool (#1287) 2025-07-24 16:18:04 -04:00
Dax Raad 03cd495c20 ci: tweak
publish / publish (push) Waiting to run
2025-07-24 15:55:45 -04:00
Dax Raad 85c4cd83bc ci: tweak
publish / publish (push) Waiting to run
2025-07-24 15:51:33 -04:00
Dax Raad a480809965 includ baseline builds
publish / publish (push) Waiting to run
2025-07-24 14:37:38 -04:00
Jesse van der Pluijm 5c1d6d3c8d Check if modelID includes "claude" for antropic/claude prompt caching (#1284) 2025-07-24 11:31:28 -04:00
Dax Raad 99f1c60633 disable snapshots
publish / publish (push) Waiting to run
2025-07-24 11:08:20 -04:00
Aiden Cline cbffb6baad fix: slog error log serialization (#1276) 2025-07-24 07:19:00 -05:00
danielfyhr c1ce8564d2 add aura theme (#1280) 2025-07-24 07:17:27 -05:00
GitHub Action a6e69ae533 ignore: update download stats 2025-07-24 2025-07-24 12:04:18 +00:00
Dax Raad da84388d6c disable undo/redo for now 2025-07-23 21:02:13 -04:00
Rico Sta. Cruz cd758913cc fix: update max visible height in list tests (#1269) 2025-07-23 20:49:15 -04:00
Dax Raad 1d0162ebae fix header width 2025-07-23 20:48:35 -04:00
Dax Raad 0475fb5137 wip: always force create snapshot 2025-07-23 20:46:43 -04:00
Dax Raad cbf56d2cbd wip: fix redoing 2025-07-23 20:42:02 -04:00
Dax 11d236609d basic undo feature (#1268)
Co-authored-by: adamdotdevin <2363879+adamdottv@users.noreply.github.com>
Co-authored-by: Jay V <air@live.ca>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Andrew Joslin <andrew@ajoslin.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Tobias Walle <9933601+tobias-walle@users.noreply.github.com>
2025-07-23 20:30:46 -04:00
Yihui Khuu 9e80e6d855 feat: pass mode into task tool (#1248) 2025-07-23 20:29:59 -04:00
Aiden Cline 2e376833f6 docs: remove deprecated 'log_level' reference in docs (#1258) 2025-07-23 18:53:58 -04:00
Aiden Cline 4caae581b8 tweak: handle pasted attachment references (#1257) 2025-07-23 15:41:17 -05:00
Tobias Walle 1b848a00a5 fix "working" spinner animation (#1054) (#1259) 2025-07-23 15:40:34 -05:00
Dax Raad c2c65c796a remove providers path
publish / publish (push) Waiting to run
2025-07-23 12:15:31 -04:00
Dax Raad 38b4d1e03d add debug paths command 2025-07-23 12:14:54 -04:00
GitHub Action 117d54e948 ignore: update download stats 2025-07-23 2025-07-23 12:04:18 +00:00
Aiden Cline 7f3c98aa1f tweak: ensure most recently interacted with session appears at the top (#1239) 2025-07-22 22:37:36 -05:00
Dax Raad 1acf196e98 config: improve config schema
publish / publish (push) Waiting to run
2025-07-22 20:35:40 -04:00
Jay V 36abbe1d7b docs: edit ide 2025-07-22 19:02:30 -04:00
Andrew Joslin 7ac284c977 Allow multiline prompts for github agent (#1225) 2025-07-22 18:30:51 -04:00
Aiden Cline 774678077f feat(tui): support pipe into tui (#1230) 2025-07-22 17:19:20 -05:00
Jay V 7ed687975e docs: add tutorial closes #740 2025-07-22 17:54:53 -04:00
Frank a382ad9b1c wip: vscode extension 2025-07-22 17:13:58 -04:00
Dax Raad 4b52e5bd49 ci: error github api fail 2025-07-22 17:06:06 -04:00
Frank c6eed8c6fe wip: vscode extension 2025-07-22 16:50:56 -04:00
Frank 824da2a300 wip: vscode extension
publish / publish (push) Waiting to run
2025-07-22 16:46:44 -04:00
Frank 06bee6d089 wip: vscode extension 2025-07-22 16:46:44 -04:00
Frank 76fb049963 wip: vscode extension 2025-07-22 16:46:44 -04:00
Dax Raad 0eebf55d07 ignore: lock changes 2025-07-22 15:49:36 -04:00
Dax Raad 09e8d33f5f wip: tui api 2025-07-22 15:49:24 -04:00
Frank 23aa869162 wip: vscode extension
publish-vscode / publish (push) Waiting to run
2025-07-22 15:36:55 -04:00
Frank 64d43e06ec wip: vscode extension 2025-07-22 15:28:09 -04:00
Frank c7027ea017 wip: vscode extension 2025-07-22 13:21:49 -04:00
Aiden Cline 6eb987cbb9 tweak: cleanup cancelled markdown (#1222) 2025-07-22 12:08:03 -05:00
adamdotdevin 0b2d6c20ff chore: generate sdk into packages/sdk 2025-07-22 11:50:51 -05:00
Dax Raad f4ecb5e90b wip: append-prompt is better 2025-07-22 12:27:02 -04:00
Dax Raad 9dd85ea2c7 wip: tui api 2025-07-22 12:15:50 -04:00
Frank eca975848a wip: vscode extension 2025-07-22 11:21:29 -04:00
adamdotdevin a05547f189 fix(tui): more defensive attachment conversion
publish / publish (push) Waiting to run
2025-07-22 09:28:13 -05:00
GitHub Action 51aba439ec ignore: update download stats 2025-07-22 2025-07-22 12:04:22 +00:00
Aiden Cline 7d6d060f7d fix: mouse text selection bug (#1206) 2025-07-21 19:15:36 -05:00
Dax Raad 26e93c4d11 wip: api for tui 2025-07-21 19:53:58 -04:00
Frank cfe5f3bbbc wip: vscode extension 2025-07-21 19:10:57 -04:00
Timo Clasen bb7aec2213 feat(tui): add ctrl+p and ctrl-n to history navigation (#1199) 2025-07-21 15:10:50 -05:00
Frank cf3006d133 wip: vscode extension
publish-vscode / publish (push) Waiting to run
2025-07-21 15:48:46 -04:00
Dax Raad a6cd7c220a ci: tweaks 2025-07-21 15:45:44 -04:00
Dax Raad 4d6e7f818d fix broken attachments
publish / publish (push) Waiting to run
2025-07-21 15:38:41 -04:00
Dax Raad adf56be05f fix title generation bug
publish / publish (push) Waiting to run
2025-07-21 15:23:47 -04:00
Dax 531d035547 message queuing (#1200)
publish / publish (push) Waiting to run
2025-07-21 15:14:54 -04:00
adamdotdevin 0aec866a8c fix(tui): up/down arrow handling
publish / publish (push) Waiting to run
2025-07-21 10:44:21 -05:00
plyght fc18dbaa4c feat(tui): paste minimizing (#784)
Co-authored-by: adamdotdevin <2363879+adamdottv@users.noreply.github.com>
2025-07-21 10:31:29 -05:00
Dax Raad 6f15934a6b do not copy empty strings 2025-07-21 11:27:15 -04:00
Dax Raad d705b484c8 include newline between messages when copying
publish / publish (push) Waiting to run
2025-07-21 11:22:51 -04:00
Dax Raad adcc58a2b0 add toast for copy
publish / publish (push) Waiting to run
2025-07-21 11:19:54 -04:00
adamelmore 76a98df85f feat(tui): disable keybinds 2025-07-21 10:08:25 -05:00
adamelmore f356058fb4 docs: cleanup 2025-07-21 10:02:58 -05:00
adamelmore db24514d3e feat(tui): theme override with OPENCODE_THEME 2025-07-21 10:02:57 -05:00
adamdotdevin 4c5bbcf74e fix(tui): restore spinner ticks
publish / publish (push) Waiting to run
2025-07-21 05:58:24 -05:00
adamdotdevin b6f723f092 feat(tui): message history select with up/down arrows
publish / publish (push) Waiting to run
2025-07-21 05:52:11 -05:00
Aiden Cline e4f4915136 fix: pasting issue (#1182) 2025-07-21 04:09:16 -05:00
Aiden Cline f5180998dd fix: export cmd (#1184) 2025-07-21 04:08:26 -05:00
Dax 9b672c6b44 Update STATS.md 2025-07-20 20:36:23 -04:00
Dax Raad 22c807f5ee trimmed selection ui
publish / publish (push) Waiting to run
2025-07-20 19:36:56 -04:00
Dax Raad bce6822bcc ignore: remove log 2025-07-20 19:08:19 -04:00
Dax Raad 004f6504e2 implement copy paste much wow can you believe we went this long without it so stupid i blame adam
publish / publish (push) Waiting to run
2025-07-20 19:05:38 -04:00
Dax Raad 9278f64588 do not snapshot nongit projects for now
publish / publish (push) Waiting to run
2025-07-20 13:59:30 -04:00
Frank 4bdb686e1b wip: vscode extension
publish-vscode / publish (push) Waiting to run
2025-07-20 13:31:16 -04:00
537 changed files with 46807 additions and 9359 deletions
+4 -1
View File
@@ -17,10 +17,13 @@ jobs:
- uses: oven-sh/setup-bun@v1
with:
bun-version: 1.2.17
bun-version: 1.2.21
- run: bun install
- 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 }}
+58
View File
@@ -0,0 +1,58 @@
name: Duplicate Issue Detection
on:
issues:
types: [opened]
jobs:
check-duplicates:
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Install opencode
run: curl -fsSL https://opencode.ai/install | bash
- name: Check for duplicate issues
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENCODE_PERMISSION: |
{
"bash": {
"gh issue*": "allow",
"*": "deny"
},
"webfetch": "deny"
}
run: |
opencode run -m anthropic/claude-sonnet-4-20250514 "A new issue has been created:'
Issue number:
${{ github.event.issue.number }}
Lookup this issue and search through existing issues (excluding #${{ github.event.issue.number }}) in this repository to find any potential duplicates of this new issue.
Consider:
1. Similar titles or descriptions
2. Same error messages or symptoms
3. Related functionality or components
4. Similar feature requests
If you find any potential duplicates, please comment on the new issue with:
- A brief explanation of why it might be a duplicate
- Links to the potentially duplicate issues
- A suggestion to check those issues first
Use this format for the comment:
'This issue might be a duplicate of existing issues. Please check:
- #[issue_number]: [brief description of similarity]
Feel free to ignore if none of these address your specific case.'
If no clear duplicates are found, do not comment."
+28
View File
@@ -0,0 +1,28 @@
name: Format
on:
push:
pull_request:
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: oven-sh/setup-bun@v1
with:
bun-version: 1.2.21
- name: run
run: |
bun install
./script/format.ts
env:
CI: true
+53
View File
@@ -0,0 +1,53 @@
name: Guidelines Check
on:
# Disabled - uncomment to re-enable
# pull_request_target:
# types: [opened, synchronize]
jobs:
check-guidelines:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Install opencode
run: curl -fsSL https://opencode.ai/install | bash
- name: Check PR guidelines compliance
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENCODE_PERMISSION: '{ "bash": { "gh*": "allow", "gh pr review*": "deny", "*": "deny" } }'
run: |
opencode run -m anthropic/claude-sonnet-4-20250514 "A new pull request has been created: '${{ github.event.pull_request.title }}'
<pr-number>
${{ github.event.pull_request.number }}
</pr-number>
<pr-description>
${{ github.event.pull_request.body }}
</pr-description>
Please check all the code changes in this pull request against the guidelines in AGENTS.md file in this repository. Diffs are important but make sure you read the entire file to get proper context. Make it clear the suggestions are merely suggestions and the human can decide what to do
Use the gh cli to create comments on the files for the violations. Try to leave the comment on the exact line number. If you have a suggested fix include it in a suggestion code block.
Command MUST be like this.
```
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments \
-f 'body=[summary of issue]' -f 'commit_id=${{ github.event.pull_request.head.sha }}' -f 'path=[path-to-file]' -F "line=[line]" -f 'side=RIGHT'
```
Only create comments for actual violations. If the code follows all guidelines, don't run any gh commands."
+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:
+9 -6
View File
@@ -6,19 +6,22 @@ on:
jobs:
opencode:
if: startsWith(github.event.comment.body, 'hey opencode')
if: |
contains(github.event.comment.body, ' /oc') ||
contains(github.event.comment.body, ' /opencode')
runs-on: ubuntu-latest
permissions:
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/sdks/github@github-v1
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/sonic
+1 -1
View File
@@ -27,4 +27,4 @@ jobs:
git config --global user.email "opencode@sst.dev"
git config --global user.name "opencode"
./script/publish
working-directory: ./sdks/github
working-directory: ./github
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.2.17
bun-version: 1.2.21
- run: git fetch --force --tags
- run: bun install -g @vscode/vsce
+25 -17
View File
@@ -1,14 +1,17 @@
name: publish
run-name: "${{ format('release {0}', inputs.bump) }}"
on:
workflow_dispatch:
push:
branches:
- dev
tags:
- "*"
- "!vscode-v*"
- "!github-v*"
inputs:
bump:
description: "Bump major, minor, or patch"
required: true
type: choice
options:
- major
- minor
- patch
concurrency: ${{ github.workflow }}-${{ github.ref }}
@@ -34,32 +37,37 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.2.17
bun-version: 1.2.21
- name: Cache ~/.bun
id: cache-bun
uses: actions/cache@v3
with:
path: ~/.bun
key: ${{ runner.os }}-bun-1-2-21-${{ hashFiles('bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-1-2-21-
- name: Install makepkg
run: |
sudo apt-get update
sudo apt-get install -y pacman-package-manager
- name: Setup SSH for AUR
run: |
mkdir -p ~/.ssh
echo "${{ secrets.AUR_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts
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: Publish
run: |
bun install
if [ "${{ startsWith(github.ref, 'refs/tags/') }}" = "true" ]; then
./script/publish.ts
else
./script/publish.ts --snapshot
fi
working-directory: ./packages/opencode
./script/publish.ts
env:
OPENCODE_BUMP: ${{ inputs.bump }}
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
AUR_KEY: ${{ secrets.AUR_KEY }}
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
+3 -1
View File
@@ -21,7 +21,7 @@ jobs:
bun-version: latest
- name: Run stats script
run: bun scripts/stats.ts
run: bun script/stats.ts
- name: Commit stats
run: |
@@ -30,3 +30,5 @@ jobs:
git add STATS.md
git diff --staged --quiet || git commit -m "ignore: update download stats $(date -I)"
git push
env:
POSTHOG_KEY: ${{ secrets.POSTHOG_KEY }}
+24
View File
@@ -0,0 +1,24 @@
name: Typecheck
on:
pull_request:
branches: [dev]
workflow_dispatch:
jobs:
typecheck:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: 1.2.21
- name: Install dependencies
run: bun install
- name: Run typecheck
run: bun typecheck
+3 -1
View File
@@ -1,8 +1,10 @@
.DS_Store
node_modules
.opencode
.worktrees
.sst
.env
.idea
.vscode
openapi.json
playground
tmp
+31
View File
@@ -0,0 +1,31 @@
---
description: ALWAYS use this when writing docs
---
You are an expert technical documentation writer
You are not verbose
The title of the page should be a word or a 2-3 word phrase
The description should be one short line, should not start with "The", should
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
The section titles are short with only the first letter of the word capitalized
The section titles are in the imperative mood
The section titles should not repeat the term used in the page title, for
example, if the page title is "Models", avoid using a section title like "Add
new models". This might be unavoidable in some cases, but try to avoid it.
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:`
+10
View File
@@ -0,0 +1,10 @@
---
description: Use this agent when you are asked to commit and push code changes to a git repository.
mode: subagent
---
You commit and push to git
Commit messages should be brief since they are used to generate release notes.
Messages should say WHY the change was made and not WHAT was changed.
+9
View File
@@ -0,0 +1,9 @@
commit and push
make sure it includes a prefix like
docs:
tui:
core:
ci:
ignore:
wip:
+8
View File
@@ -0,0 +1,8 @@
---
description: hello world
---
hey there $ARGUMENTS
!`ls`
check out @README.md
+13 -12
View File
@@ -1,15 +1,16 @@
# TUI Agent Guidelines
## IMPORTANT
## Style
- Try to keep things in one function unless composable or reusable
- DO NOT do unnecessary destructuring of variables
- DO NOT use `else` statements unless necessary
- DO NOT use `try`/`catch` if it can be avoided
- AVOID `try`/`catch` where possible
- AVOID `else` statements
- AVOID using `any` type
- AVOID `let` statements
- PREFER single word variable names where possible
- Use as many bun apis as possible like Bun.file()
- prefer single word variable/function names
- avoid try catch where possible - prefer to let exceptions bubble up
- avoid else statements where possible
- do not make useless helper functions - inline functionality unless the
function is reusable or composable
- prefer Bun apis
## Debugging
## Workflow
- you can regenerate the golang sdk by calling ./scripts/stainless.ts
- we use bun for everything
- To test opencode in the `packages/opencode` directory you can run `bun dev`
+4 -4
View File
@@ -26,7 +26,7 @@ curl -fsSL https://opencode.ai/install | bash
# Package managers
npm i -g opencode-ai@latest # or bun/pnpm/yarn
brew install sst/tap/opencode # macOS
brew install sst/tap/opencode # macOS and Linux
paru -S opencode-bin # Arch Linux
```
@@ -83,7 +83,7 @@ And run.
```bash
$ bun install
$ bun run packages/opencode/src/index.ts
$ bun dev
```
#### Development Notes
@@ -97,7 +97,7 @@ $ bun run packages/opencode/src/index.ts
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.
- 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.
@@ -107,4 +107,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)
+56 -2
View File
@@ -11,7 +11,8 @@
| 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-10 | 43,796 (+5,744) | 71,402 (+6,934) | 115,198 (+12,678) |
| 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) |
@@ -20,6 +21,59 @@
| 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-18 | 70,380 (+1) | 102,587 (+0) | 172,967 (+1) |
| 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) |
+2147 -195
View File
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
dist
.wrangler
.output
.vercel
.netlify
.vinxi
app.config.timestamp_*.js
# Environment
.env
.env*.local
# dependencies
/node_modules
# IDEs and editors
/.idea
.project
.classpath
*.launch
.settings/
# Temp
gitignore
# System Files
.DS_Store
Thumbs.db
+149
View File
@@ -0,0 +1,149 @@
---
description: use whenever you are styling a ui with css
---
you are very good at writing clean maintainable css using modern techniques
css is structured like this
```css
[data-page="home"] {
[data-component="header"] {
[data-slot="logo"] {
}
}
}
```
top level pages are scoped using `data-page`
pages can break down into components using `data-component`
components can break down into slots using `data-slot`
structure things so that this hierarchy is followed IN YOUR CSS - you should rarely need to
nest components inside other components. you should NEVER nest components inside
slots. you should NEVER nest slots inside other slots.
**IMPORTANT: This hierarchy rule applies to CSS structure, NOT JSX/DOM structure.**
The hierarchy in css file does NOT have to match the hierarchy in the dom - you
can put components or slots at the same level in CSS even if one goes inside another in the DOM.
Your JSX can nest however makes semantic sense - components can be inside slots,
slots can contain components, etc. The DOM structure should be whatever makes the most
semantic and functional sense.
It is more important to follow the pages -> components -> slots structure IN YOUR CSS,
while keeping your JSX/DOM structure logical and semantic.
use data attributes to represent different states of the component
```css
[data-component="modal"] {
opacity: 0;
&[data-state="open"] {
opacity: 1;
}
}
```
this will allow jsx to control the syling
avoid selectors that just target an element type like `> span` you should assign
it a slot name. it's ok to do this sometimes where it makes sense semantically
like targeting `li` elements in a list
in terms of file structure `./src/style/` contains all universal styling rules.
these should not contain anything specific to a page
`./src/style/token` contains all the tokens used in the project
`./src/style/component` is for reusable components like buttons or inputs
page specific styles should go next to the page they are styling so
`./src/routes/about.tsx` should have its styles in `./src/routes/about.css`
`about.css` should be scoped using `data-page="about"`
## Example of correct implementation
JSX can nest however makes sense semantically:
```jsx
<div data-slot="left">
<div data-component="title">Section Title</div>
<div data-slot="content">Content here</div>
</div>
```
CSS maintains clean hierarchy regardless of DOM nesting:
```css
[data-page="home"] {
[data-component="screenshots"] {
[data-slot="left"] {
/* styles */
}
[data-slot="content"] {
/* styles */
}
}
[data-component="title"] {
/* can be at same level even though nested in DOM */
}
}
```
## Reusable Components
If a component is reused across multiple sections of the same page, define it at the page level:
```jsx
<!-- Used in multiple places on the same page -->
<section data-component="install">
<div data-component="method">
<h3 data-component="title">npm</h3>
</div>
<div data-component="method">
<h3 data-component="title">bun</h3>
</div>
</section>
<section data-component="screenshots">
<div data-slot="left">
<div data-component="title">Screenshot Title</div>
</div>
</section>
```
```css
[data-page="home"] {
/* Reusable title component defined at page level since it's used in multiple components */
[data-component="title"] {
text-transform: uppercase;
font-weight: 400;
}
[data-component="install"] {
/* install-specific styles */
}
[data-component="screenshots"] {
/* screenshots-specific styles */
}
}
```
This is correct because the `title` component has consistent styling and behavior across the page.
## Key Clarifications
1. **JSX Nesting is Flexible**: Components can be nested inside slots, slots can contain components - whatever makes semantic sense
2. **CSS Hierarchy is Strict**: Follow pages → components → slots structure in CSS
3. **Reusable Components**: Define at the appropriate level where they're shared (page level if used across the page, component level if only used within that component)
4. **DOM vs CSS Structure**: These don't need to match - optimize each for its purpose
See ./src/routes/index.css and ./src/routes/index.tsx for a complete example.
+32
View File
@@ -0,0 +1,32 @@
# SolidStart
Everything you need to build a Solid project, powered by [`solid-start`](https://start.solidjs.com);
## Creating a project
```bash
# create a new project in the current directory
npm init solid@latest
# create a new project in my-app
npm init solid@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
Solid apps are built with _presets_, which optimise your project for deployment to different environments.
By default, `npm run build` will generate a Node app that you can run with `npm start`. To use a different preset, add it to the `devDependencies` in `package.json` and specify in your `app.config.js`.
## This project was created with the [Solid CLI](https://github.com/solidjs-community/solid-cli)
+23
View File
@@ -0,0 +1,23 @@
import { defineConfig } from "@solidjs/start/config"
export default defineConfig({
middleware: "./src/middleware.ts",
vite: {
server: {
allowedHosts: true,
},
build: {
rollupOptions: {
external: ["cloudflare:workers"],
},
minify: false,
},
},
server: {
compatibilityDate: "2024-09-19",
preset: "cloudflare_module",
cloudflare: {
nodeCompat: true,
},
},
})
+25
View File
@@ -0,0 +1,25 @@
{
"name": "@opencode/cloud-app",
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit",
"dev": "vinxi dev --host 0.0.0.0",
"dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev",
"build": "vinxi build && ../../packages/opencode/script/schema.ts ./.output/public/config.json",
"start": "vinxi start",
"version": "0.7.7"
},
"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": "catalog:",
"vinxi": "^0.5.7",
"@opencode/cloud-core": "workspace:*"
},
"engines": {
"node": ">=22"
}
}
+5
View File
@@ -0,0 +1,5 @@
<svg width="600" height="600" viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="600" height="600" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M115 180H300V420H115V180ZM253.75 229.044H161.25V370.405H253.75V229.044Z" fill="white"/>
<path d="M346.25 180H485V229.044H392.5V370.405H485V419.449H346.25V180Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 377 B

+5
View File
@@ -0,0 +1,5 @@
User-agent: *
Allow: /
# Disallow shared content pages
Disallow: /s/
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+182
View File
@@ -0,0 +1,182 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"$schema": {
"type": "string",
"description": "JSON schema reference for configuration validation"
},
"defs": {
"type": "object",
"description": "Color definitions that can be referenced in the theme",
"patternProperties": {
"^[a-zA-Z][a-zA-Z0-9_]*$": {
"oneOf": [
{
"type": "string",
"pattern": "^#[0-9a-fA-F]{6}$",
"description": "Hex color value"
},
{
"type": "integer",
"minimum": 0,
"maximum": 255,
"description": "ANSI color code (0-255)"
},
{
"type": "string",
"enum": ["none"],
"description": "No color (uses terminal default)"
}
]
}
},
"additionalProperties": false
},
"theme": {
"type": "object",
"description": "Theme color definitions",
"properties": {
"primary": { "$ref": "#/definitions/colorValue" },
"secondary": { "$ref": "#/definitions/colorValue" },
"accent": { "$ref": "#/definitions/colorValue" },
"error": { "$ref": "#/definitions/colorValue" },
"warning": { "$ref": "#/definitions/colorValue" },
"success": { "$ref": "#/definitions/colorValue" },
"info": { "$ref": "#/definitions/colorValue" },
"text": { "$ref": "#/definitions/colorValue" },
"textMuted": { "$ref": "#/definitions/colorValue" },
"background": { "$ref": "#/definitions/colorValue" },
"backgroundPanel": { "$ref": "#/definitions/colorValue" },
"backgroundElement": { "$ref": "#/definitions/colorValue" },
"border": { "$ref": "#/definitions/colorValue" },
"borderActive": { "$ref": "#/definitions/colorValue" },
"borderSubtle": { "$ref": "#/definitions/colorValue" },
"diffAdded": { "$ref": "#/definitions/colorValue" },
"diffRemoved": { "$ref": "#/definitions/colorValue" },
"diffContext": { "$ref": "#/definitions/colorValue" },
"diffHunkHeader": { "$ref": "#/definitions/colorValue" },
"diffHighlightAdded": { "$ref": "#/definitions/colorValue" },
"diffHighlightRemoved": { "$ref": "#/definitions/colorValue" },
"diffAddedBg": { "$ref": "#/definitions/colorValue" },
"diffRemovedBg": { "$ref": "#/definitions/colorValue" },
"diffContextBg": { "$ref": "#/definitions/colorValue" },
"diffLineNumber": { "$ref": "#/definitions/colorValue" },
"diffAddedLineNumberBg": { "$ref": "#/definitions/colorValue" },
"diffRemovedLineNumberBg": { "$ref": "#/definitions/colorValue" },
"markdownText": { "$ref": "#/definitions/colorValue" },
"markdownHeading": { "$ref": "#/definitions/colorValue" },
"markdownLink": { "$ref": "#/definitions/colorValue" },
"markdownLinkText": { "$ref": "#/definitions/colorValue" },
"markdownCode": { "$ref": "#/definitions/colorValue" },
"markdownBlockQuote": { "$ref": "#/definitions/colorValue" },
"markdownEmph": { "$ref": "#/definitions/colorValue" },
"markdownStrong": { "$ref": "#/definitions/colorValue" },
"markdownHorizontalRule": { "$ref": "#/definitions/colorValue" },
"markdownListItem": { "$ref": "#/definitions/colorValue" },
"markdownListEnumeration": { "$ref": "#/definitions/colorValue" },
"markdownImage": { "$ref": "#/definitions/colorValue" },
"markdownImageText": { "$ref": "#/definitions/colorValue" },
"markdownCodeBlock": { "$ref": "#/definitions/colorValue" },
"syntaxComment": { "$ref": "#/definitions/colorValue" },
"syntaxKeyword": { "$ref": "#/definitions/colorValue" },
"syntaxFunction": { "$ref": "#/definitions/colorValue" },
"syntaxVariable": { "$ref": "#/definitions/colorValue" },
"syntaxString": { "$ref": "#/definitions/colorValue" },
"syntaxNumber": { "$ref": "#/definitions/colorValue" },
"syntaxType": { "$ref": "#/definitions/colorValue" },
"syntaxOperator": { "$ref": "#/definitions/colorValue" },
"syntaxPunctuation": { "$ref": "#/definitions/colorValue" }
},
"required": ["primary", "secondary", "accent", "text", "textMuted", "background"],
"additionalProperties": false
}
},
"required": ["theme"],
"additionalProperties": false,
"definitions": {
"colorValue": {
"oneOf": [
{
"type": "string",
"pattern": "^#[0-9a-fA-F]{6}$",
"description": "Hex color value (same for dark and light)"
},
{
"type": "integer",
"minimum": 0,
"maximum": 255,
"description": "ANSI color code (0-255, same for dark and light)"
},
{
"type": "string",
"enum": ["none"],
"description": "No color (uses terminal default)"
},
{
"type": "string",
"pattern": "^[a-zA-Z][a-zA-Z0-9_]*$",
"description": "Reference to another color in the theme or defs"
},
{
"type": "object",
"properties": {
"dark": {
"oneOf": [
{
"type": "string",
"pattern": "^#[0-9a-fA-F]{6}$",
"description": "Hex color value for dark mode"
},
{
"type": "integer",
"minimum": 0,
"maximum": 255,
"description": "ANSI color code for dark mode"
},
{
"type": "string",
"enum": ["none"],
"description": "No color (uses terminal default)"
},
{
"type": "string",
"pattern": "^[a-zA-Z][a-zA-Z0-9_]*$",
"description": "Reference to another color for dark mode"
}
]
},
"light": {
"oneOf": [
{
"type": "string",
"pattern": "^#[0-9a-fA-F]{6}$",
"description": "Hex color value for light mode"
},
{
"type": "integer",
"minimum": 0,
"maximum": 255,
"description": "ANSI color code for light mode"
},
{
"type": "string",
"enum": ["none"],
"description": "No color (uses terminal default)"
},
{
"type": "string",
"pattern": "^[a-zA-Z][a-zA-Z0-9_]*$",
"description": "Reference to another color for light mode"
}
]
}
},
"required": ["dark", "light"],
"additionalProperties": false,
"description": "Separate colors for dark and light modes"
}
]
}
}
}
+1
View File
@@ -0,0 +1 @@
@import "./style/index.css";
+23
View File
@@ -0,0 +1,23 @@
import { MetaProvider, Title, Meta } from "@solidjs/meta"
import { Router } from "@solidjs/router"
import { FileRoutes } from "@solidjs/start/router"
import { ErrorBoundary, Suspense } from "solid-js"
import "@ibm/plex/css/ibm-plex.css"
import "./app.css"
export default function App() {
return (
<Router
explicitLinks={true}
root={(props) => (
<MetaProvider>
<Title>opencode</Title>
<Meta name="description" content="opencode - The AI coding agent built for the terminal." />
<Suspense>{props.children}</Suspense>
</MetaProvider>
)}
>
<FileRoutes />
</Router>
)
}
+2
View File
@@ -0,0 +1,2 @@
<svg xmlns="http://www.w3.org/2000/svg" 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"/></svg>

After

Width:  |  Height:  |  Size: 212 B

+2
View File
@@ -0,0 +1,2 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" 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"/><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"/></svg>

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 902 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 998 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 KiB

+19
View File
@@ -0,0 +1,19 @@
<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>

After

Width:  |  Height:  |  Size: 1.6 KiB

+18
View File
@@ -0,0 +1,18 @@
<svg width="288" height="50" viewBox="0 0 288 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 16.5H24V33H8V16.5Z" fill="black" fill-opacity="0.15"/>
<path d="M48 16.5H64V33H48V16.5Z" fill="black" fill-opacity="0.15"/>
<path d="M120 16.5H136V33H120V16.5Z" fill="black" fill-opacity="0.15"/>
<path d="M160 16.5H176V33H160V16.5Z" fill="black" fill-opacity="0.15"/>
<path d="M192 16.5H208V33H192V16.5Z" fill="black" fill-opacity="0.15"/>
<path d="M232 16.5H248V33H232V16.5Z" fill="black" fill-opacity="0.15"/>
<path d="M264 0H288V8.5H272V16.5H288V25H272V33H288V41.5H264V0Z" fill="black" fill-opacity="0.95"/>
<path d="M248 0H224V41.5H248V33H232V8.5H248V0Z" fill="black" fill-opacity="0.95"/>
<path d="M256 8.5H248V33H256V8.5Z" fill="black" fill-opacity="0.95"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M184 0H216V41.5H184V0ZM208 8.5H192V33H208V8.5Z" fill="black" fill-opacity="0.95"/>
<path d="M144 8.5H136V41.5H144V8.5Z" fill="black" fill-opacity="0.55"/>
<path d="M136 0H112V41.5H120V8.5H136V0Z" fill="black" fill-opacity="0.55"/>
<path d="M80 0H104V8.5H88V16.5H104V25H88V33H104V41.5H80V0Z" fill="black" fill-opacity="0.55"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M40 0H72V41.5H48V49.5H40V0ZM64 8.5H48V33H64V8.5Z" fill="black" fill-opacity="0.55"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H32V41.5955H0V0ZM24 8.5H8V33H24V8.5Z" fill="black" fill-opacity="0.55"/>
<path d="M152 0H176V8.5H160V33H176V41.5H152V0Z" fill="black" fill-opacity="0.95"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+12
View File
@@ -0,0 +1,12 @@
<svg width="289" height="50" viewBox="0 0 289 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M264.5 0H288.5V8.5H272.5V16.5H288.5V25H272.5V33H288.5V41.5H264.5V0Z" fill="black"/>
<path d="M248.5 0H224.5V41.5H248.5V33H232.5V8.5H248.5V0Z" fill="black"/>
<path d="M256.5 8.5H248.5V33H256.5V8.5Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M184.5 0H216.5V41.5H184.5V0ZM208.5 8.5H192.5V33H208.5V8.5Z" fill="black"/>
<path d="M144.5 8.5H136.5V41.5H144.5V8.5Z" fill="black"/>
<path d="M136.5 0H112.5V41.5H120.5V8.5H136.5V0Z" fill="black"/>
<path d="M80.5 0H104.5V8.5H88.5V16.5H104.5V25H88.5V33H104.5V41.5H80.5V0Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M40.5 0H72.5V41.5H48.5V49.5H40.5V0ZM64.5 8.5H48.5V33H64.5V8.5Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.5 0H32.5V41.5955H0.5V0ZM24.5 8.5H8.5V33H24.5V8.5Z" fill="black"/>
<path d="M152.5 0H176.5V8.5H160.5V33H176.5V41.5H152.5V0Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 981 B

+71
View File
@@ -0,0 +1,71 @@
import { JSX } from "solid-js"
export function IconLogo(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
return (
<svg {...props} viewBox="0 0 289 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M264.5 0H288.5V8.5H272.5V16.5H288.5V25H272.5V33H288.5V41.5H264.5V0Z" fill="currentColor" />
<path d="M248.5 0H224.5V41.5H248.5V33H232.5V8.5H248.5V0Z" fill="currentColor" />
<path d="M256.5 8.5H248.5V33H256.5V8.5Z" fill="currentColor" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M184.5 0H216.5V41.5H184.5V0ZM208.5 8.5H192.5V33H208.5V8.5Z"
fill="currentColor"
/>
<path d="M144.5 8.5H136.5V41.5H144.5V8.5Z" fill="currentColor" />
<path d="M136.5 0H112.5V41.5H120.5V8.5H136.5V0Z" fill="currentColor" />
<path d="M80.5 0H104.5V8.5H88.5V16.5H104.5V25H88.5V33H104.5V41.5H80.5V0Z" fill="currentColor" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M40.5 0H72.5V41.5H48.5V49.5H40.5V0ZM64.5 8.5H48.5V33H64.5V8.5Z"
fill="currentColor"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M0.5 0H32.5V41.5955H0.5V0ZM24.5 8.5H8.5V33H24.5V8.5Z"
fill="currentColor"
/>
<path d="M152.5 0H176.5V8.5H160.5V33H176.5V41.5H152.5V0Z" fill="currentColor" />
</svg>
)
}
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>
)
}
+23
View File
@@ -0,0 +1,23 @@
import { useSession } from "vinxi/http"
export interface AuthSession {
account?: Record<
string,
{
id: string
email: string
}
>
current?: string
}
export function useAuthSession() {
return useSession<AuthSession>({
password: "0".repeat(32),
name: "auth",
cookie: {
secure: false,
httpOnly: true,
},
})
}
+83
View File
@@ -0,0 +1,83 @@
import { getRequestEvent } from "solid-js/web"
import { and, Database, eq, inArray } from "@opencode/cloud-core/drizzle/index.js"
import { WorkspaceTable } from "@opencode/cloud-core/schema/workspace.sql.js"
import { UserTable } from "@opencode/cloud-core/schema/user.sql.js"
import { redirect } from "@solidjs/router"
import { AccountTable } from "@opencode/cloud-core/schema/account.sql.js"
import { Actor } from "@opencode/cloud-core/actor.js"
import { createClient } from "@openauthjs/openauth/client"
import { useAuthSession } from "./auth.session"
export const AuthClient = createClient({
clientID: "app",
issuer: import.meta.env.VITE_AUTH_URL,
})
export const getActor = async (workspace?: string): Promise<Actor.Info> => {
"use server"
const evt = getRequestEvent()
if (!evt) throw new Error("No request event")
if (evt.locals.actor) return evt.locals.actor
evt.locals.actor = (async () => {
const auth = await useAuthSession()
if (!workspace) {
const account = auth.data.account ?? {}
const current = account[auth.data.current ?? ""]
if (current) {
return {
type: "account",
properties: {
email: current.email,
accountID: current.id,
},
}
}
if (Object.keys(account).length > 0) {
const current = Object.values(account)[0]
await auth.update((val) => ({
...val,
current: current.id,
}))
return {
type: "account",
properties: {
email: current.email,
accountID: current.id,
},
}
}
return {
type: "public",
properties: {},
}
}
const accounts = Object.keys(auth.data.account ?? {})
if (accounts.length) {
const result = await Database.transaction(async (tx) => {
return await tx
.select({
user: UserTable,
})
.from(AccountTable)
.innerJoin(UserTable, and(eq(UserTable.email, AccountTable.email)))
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, UserTable.workspaceID))
.where(and(inArray(AccountTable.id, accounts), eq(WorkspaceTable.id, workspace)))
.limit(1)
.execute()
.then((x) => x[0])
})
if (result) {
return {
type: "user",
properties: {
userID: result.user.id,
workspaceID: result.user.workspaceID,
},
}
}
}
throw redirect("/auth/authorize")
})()
return evt.locals.actor
}
+7
View File
@@ -0,0 +1,7 @@
import { Actor } from "@opencode/cloud-core/actor.js"
import { getActor } from "./auth"
export async function withActor<T>(fn: () => T, workspace?: string) {
const actor = await getActor(workspace)
return Actor.provide(actor.type, actor.properties, fn)
}
+4
View File
@@ -0,0 +1,4 @@
// @refresh reload
import { mount, StartClient } from "@solidjs/start/client"
mount(() => <StartClient />, document.getElementById("app")!)
+28
View File
@@ -0,0 +1,28 @@
// @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.svg" />
<meta property="og:image" content="/social-share.png" />
<meta property="twitter:image" content="/social-share.png" />
{assets}
</head>
<body>
<div id="app">{children}</div>
{scripts}
</body>
</html>
)}
/>
),
{
mode: "async",
},
)
+1
View File
@@ -0,0 +1 @@
/// <reference types="@solidjs/start/env" />
+5
View File
@@ -0,0 +1,5 @@
import { defineMiddleware } from "vinxi/http"
export default defineMiddleware({
onBeforeResponse() {},
})
+130
View File
@@ -0,0 +1,130 @@
[data-page="not-found"] {
--color-text: hsl(224, 10%, 10%);
--color-text-secondary: hsl(224, 7%, 46%);
--color-text-dimmed: hsl(224, 6%, 63%);
--color-text-inverted: hsl(0, 0%, 100%);
--color-border: hsl(224, 6%, 77%);
}
[data-page="not-found"] {
@media (prefers-color-scheme: dark) {
--color-text: hsl(0, 0%, 100%);
--color-text-secondary: hsl(224, 6%, 66%);
--color-text-dimmed: hsl(224, 7%, 46%);
--color-text-inverted: hsl(224, 10%, 10%);
--color-border: hsl(224, 6%, 36%);
}
}
[data-page="not-found"] {
--padding: 3rem;
--vertical-padding: 1.5rem;
--heading-font-size: 1.375rem;
@media (max-width: 30rem) {
--padding: 1rem;
--vertical-padding: 0.75rem;
--heading-font-size: 1rem;
}
font-family: var(--font-mono);
color: var(--color-text);
padding: calc(var(--padding) + 1rem);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
a {
color: var(--color-text);
text-decoration: underline;
text-underline-offset: var(--space-0-75);
text-decoration-thickness: 1px;
}
[data-component="content"] {
max-width: 40rem;
width: 100%;
border: 1px solid var(--color-border);
}
[data-component="top"] {
padding: var(--padding);
display: flex;
flex-direction: column;
align-items: center;
gap: calc(var(--vertical-padding) / 2);
text-align: center;
[data-slot="logo-link"] {
text-decoration: none;
}
img {
height: auto;
width: clamp(200px, 85vw, 400px);
}
[data-slot="logo dark"] {
display: none;
}
@media (prefers-color-scheme: dark) {
[data-slot="logo light"] {
display: none;
}
[data-slot="logo dark"] {
display: block;
}
}
[data-slot="title"] {
line-height: 1.25;
font-weight: 500;
text-align: center;
font-size: var(--heading-font-size);
color: var(--color-text);
text-transform: uppercase;
margin: 0;
}
}
[data-component="actions"] {
border-top: 1px solid var(--color-border);
display: flex;
[data-slot="action"] {
flex: 1;
text-align: center;
line-height: 1.4;
padding: var(--vertical-padding) 1rem;
text-transform: uppercase;
font-size: 1rem;
a {
display: block;
width: 100%;
height: 100%;
color: var(--color-text);
text-decoration: underline;
text-underline-offset: var(--space-0-75);
text-decoration-thickness: 1px;
}
}
[data-slot="action"] + [data-slot="action"] {
border-left: 1px solid var(--color-border);
}
@media (max-width: 40rem) {
flex-direction: column;
[data-slot="action"] + [data-slot="action"] {
border-left: none;
border-top: 1px solid var(--color-border);
}
}
}
}
+38
View File
@@ -0,0 +1,38 @@
import "./[...404].css"
import { Title } from "@solidjs/meta"
import { HttpStatusCode } from "@solidjs/start"
import logoLight from "../asset/logo-ornate-light.svg"
import logoDark from "../asset/logo-ornate-dark.svg"
export default function NotFound() {
return (
<main data-page="not-found">
<Title>Not Found | opencode</Title>
<HttpStatusCode code={404} />
<div data-component="content">
<section data-component="top">
<a href="/" data-slot="logo-link">
<img data-slot="logo light" src={logoLight} alt="opencode logo light" />
<img data-slot="logo dark" src={logoDark} alt="opencode logo dark" />
</a>
<h1 data-slot="title">404 - Page Not Found</h1>
</section>
<section data-component="actions">
<div data-slot="action">
<a href="/">Home</a>
</div>
<div data-slot="action">
<a href="/docs">Docs</a>
</div>
<div data-slot="action">
<a href="https://github.com/sst/opencode">GitHub</a>
</div>
<div data-slot="action">
<a href="/discord">Discord</a>
</div>
</section>
</div>
</main>
)
}
+7
View File
@@ -0,0 +1,7 @@
import type { APIEvent } from "@solidjs/start/server"
import { AuthClient } from "~/context/auth"
export async function GET(input: APIEvent) {
const result = await AuthClient.authorize(new URL("./callback", input.request.url).toString(), "code")
return Response.redirect(result.url, 302)
}
+31
View File
@@ -0,0 +1,31 @@
import { redirect } from "@solidjs/router"
import type { APIEvent } from "@solidjs/start/server"
import { AuthClient } from "~/context/auth"
import { useAuthSession } from "~/context/auth.session"
export async function GET(input: APIEvent) {
const url = new URL(input.request.url)
const code = url.searchParams.get("code")
if (!code) throw new Error("No code found")
const result = await AuthClient.exchange(code, `${url.origin}${url.pathname}`)
if (result.err) {
throw new Error(result.err.message)
}
const decoded = AuthClient.decode(result.tokens.access, {} as any)
if (decoded.err) throw new Error(decoded.err.message)
const session = await useAuthSession()
const id = decoded.subject.properties.accountID
await session.update((value) => {
return {
...value,
account: {
[id]: {
id,
email: decoded.subject.properties.email,
},
},
current: id,
}
})
return redirect("/auth")
}
+13
View File
@@ -0,0 +1,13 @@
import { Account } from "@opencode/cloud-core/account.js"
import { redirect } from "@solidjs/router"
import type { APIEvent } from "@solidjs/start/server"
import { withActor } from "~/context/auth.withActor"
export async function GET(input: APIEvent) {
try {
const workspaces = await withActor(async () => Account.workspaces())
return redirect(`/workspace/${workspaces[0].id}`)
} catch {
return redirect("/auth/authorize")
}
}
+13
View File
@@ -0,0 +1,13 @@
import type { APIEvent } from "@solidjs/start/server"
import { json } from "@solidjs/router"
import { Database } from "@opencode/cloud-core/drizzle/index.js"
import { UserTable } from "@opencode/cloud-core/schema/user.sql.js"
export async function GET(evt: APIEvent) {
return json({
data: await Database.use(async (tx) => {
const result = await tx.$count(UserTable)
return result
}),
})
}
+5
View File
@@ -0,0 +1,5 @@
import { redirect } from "@solidjs/router"
export async function GET() {
return redirect("https://discord.gg/opencode")
}
+20
View File
@@ -0,0 +1,20 @@
import type { APIEvent } from "@solidjs/start/server"
async function handler(evt: APIEvent) {
const req = evt.request.clone()
const url = new URL(req.url)
const targetUrl = `https://docs.opencode.ai${url.pathname}${url.search}`
const response = await fetch(targetUrl, {
method: req.method,
headers: req.headers,
body: req.body,
})
return response
}
export const GET = handler
export const POST = handler
export const PUT = handler
export const DELETE = handler
export const OPTIONS = handler
export const PATCH = handler
+20
View File
@@ -0,0 +1,20 @@
import type { APIEvent } from "@solidjs/start/server"
async function handler(evt: APIEvent) {
const req = evt.request.clone()
const url = new URL(req.url)
const targetUrl = `https://docs.opencode.ai${url.pathname}${url.search}`
const response = await fetch(targetUrl, {
method: req.method,
headers: req.headers,
body: req.body,
})
return response
}
export const GET = handler
export const POST = handler
export const PUT = handler
export const DELETE = handler
export const OPTIONS = handler
export const PATCH = handler
+504
View File
@@ -0,0 +1,504 @@
[data-page="home"] {
--color-text: hsl(224, 10%, 10%);
--color-text-secondary: hsl(224, 7%, 46%);
--color-text-dimmed: hsl(224, 6%, 63%);
--color-text-inverted: hsl(0, 0%, 100%);
--color-border: hsl(224, 6%, 77%);
}
[data-page="home"] {
@media (prefers-color-scheme: dark) {
--color-text: hsl(0, 0%, 100%);
--color-text-secondary: hsl(224, 6%, 66%);
--color-text-dimmed: hsl(224, 7%, 46%);
--color-text-inverted: hsl(224, 10%, 10%);
--color-border: hsl(224, 6%, 36%);
}
}
[data-page="home"] {
--padding: 3rem;
--vertical-padding: 1.5rem;
--heading-font-size: 1.375rem;
@media (max-width: 30rem) {
--padding: 1rem;
--vertical-padding: 0.75rem;
--heading-font-size: 1rem;
}
display: flex;
gap: var(--vertical-padding);
flex-direction: column;
font-family: var(--font-mono);
color: var(--color-text);
padding: calc(var(--padding) + 1rem);
a {
color: var(--color-text);
text-decoration: underline;
text-underline-offset: var(--space-0-75);
text-decoration-thickness: 1px;
}
[data-component="content"] {
max-width: 67.5rem;
margin: 0 auto;
border: 1px solid var(--color-border);
}
[data-component="top"] {
padding: calc(var(--padding) * 1.5) var(--padding) var(--padding);
position: relative;
display: flex;
flex-direction: column;
align-items: center;
gap: calc(var(--vertical-padding) / 2);
img {
height: auto;
width: clamp(200px, 85vw, 552px);
}
[data-slot="logo dark"] {
display: none;
}
@media (prefers-color-scheme: dark) {
[data-slot="logo light"] {
display: none;
}
[data-slot="logo dark"] {
display: block;
}
}
[data-slot="title"] {
line-height: 1.25;
font-weight: 500;
text-align: center;
font-size: var(--heading-font-size);
color: var(--color-text-secondary);
text-transform: uppercase;
}
[data-slot="login"] {
position: absolute;
top: 0;
right: 0;
border-width: 0 0 1px 1px;
border-style: solid;
border-color: var(--color-border);
background-color: var(--color-bg);
@media (max-width: 30rem) {
display: none;
}
a {
display: block;
padding: 0.5rem 1rem calc(0.5rem + 4px);
}
}
}
[data-component="cta"] {
border-top: 1px solid var(--color-border);
display: flex;
& > div + div {
border-left: 1px solid var(--color-border);
}
[data-slot="left"] {
flex: 0 0 auto;
text-align: center;
line-height: 1.4;
padding: var(--vertical-padding) 2rem;
text-transform: uppercase;
font-size: 1.125rem;
@media (max-width: 30rem) {
font-size: 1rem;
padding-bottom: calc(var(--vertical-padding) + 4px);
}
@media (max-width: 30rem) {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
}
[data-slot="center"] {
display: none;
@media (max-width: 30rem) {
display: block;
flex: 1;
text-align: center;
padding: var(--vertical-padding) 0.5rem;
border-top: 1px solid var(--color-border);
border-left: none;
}
}
[data-slot="right"] {
flex: 1;
padding: var(--vertical-padding) 1rem;
}
@media (max-width: 50rem) {
flex-direction: column;
[data-slot="right"] {
border-left: none;
border-top: 1px solid var(--color-border);
}
}
[data-slot="command"] {
all: unset;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: var(--color-text-secondary);
font-size: 1.125rem;
font-family: var(--font-mono);
gap: var(--space-2);
width: 100%;
& > span {
@media (max-width: 24rem) {
font-size: 0.875rem;
}
@media (max-width: 56rem) {
[data-slot="protocol"] {
display: none;
}
}
@media (max-width: 38rem) {
text-align: center;
span:first-child {
display: block;
}
}
}
}
[data-slot="highlight"] {
color: var(--color-text);
font-weight: 500;
}
}
[data-component="features"] {
border-top: 1px solid var(--color-border);
padding: var(--padding);
[data-slot="list"] {
padding-left: var(--space-4);
margin: 0;
list-style: disc;
li {
margin-bottom: var(--space-4);
line-height: 1.6;
strong {
text-transform: uppercase;
font-weight: 600;
}
label {
line-height: 1;
text-transform: uppercase;
font-size: 0.75rem;
letter-spacing: 0.03125rem;
background: var(--color-border);
padding: 0.125rem 0.375rem;
color: var(--color-text-inverted);
}
}
li:last-child {
margin-bottom: 0;
}
}
}
[data-component="install"] {
border-top: 1px 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="method"] {
display: flex;
padding: calc(var(--vertical-padding) / 2) calc(var(--padding) / 2) calc(var(--vertical-padding) / 2 + 0.125rem);
flex-direction: column;
text-align: left;
gap: var(--space-2-5);
@media (max-width: 30rem) {
gap: 0.3125rem;
}
@media (max-width: 40rem) {
text-align: left;
}
&:nth-child(2) {
border-left: 1px solid var(--color-border);
@media (max-width: 40rem) {
border-left: none;
border-top: 1px solid var(--color-border);
}
}
&:nth-child(3) {
border-top: 1px solid var(--color-border);
}
&:nth-child(4) {
border-top: 1px solid var(--color-border);
border-left: 1px solid var(--color-border);
@media (max-width: 40rem) {
border-left: none;
}
}
[data-component="title"] {
letter-spacing: -0.03125rem;
text-transform: uppercase;
font-weight: normal;
font-size: 1rem;
flex-shrink: 0;
color: var(--color-text-dimmed);
@media (max-width: 30rem) {
font-size: 0.75rem;
}
}
[data-slot="button"] {
all: unset;
cursor: pointer;
display: flex;
align-items: center;
color: var(--color-text-secondary);
gap: var(--space-2-5);
font-size: 1rem;
@media (max-width: 24rem) {
font-size: 0.875rem;
}
strong {
color: var(--color-text);
font-weight: 500;
}
@media (max-width: 40rem) {
justify-content: flex-start;
}
@media (max-width: 30rem) {
justify-content: center;
}
}
}
[data-component="screenshots"] {
border-top: 1px solid var(--color-border);
figure {
flex: 1;
display: flex;
flex-direction: column;
gap: calc(var(--padding) / 4);
padding: calc(var(--padding) / 2);
border-width: 0;
border-style: solid;
border-color: var(--color-border);
min-height: 0;
overflow: hidden;
& > div,
figcaption {
display: flex;
align-items: center;
}
& > div {
flex: 1;
min-height: 0;
display: flex;
align-items: center;
justify-content: center;
}
a {
display: flex;
flex: 1;
min-height: 0;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
figcaption {
letter-spacing: -0.03125rem;
text-transform: uppercase;
color: var(--color-text-dimmed);
flex-shrink: 0;
@media (max-width: 30rem) {
font-size: 0.75rem;
}
}
}
& > [data-slot="left"] figure {
height: var(--images-height);
box-sizing: border-box;
}
& > [data-slot="right"] figure {
height: calc(var(--images-height) / 2);
box-sizing: border-box;
}
& > [data-slot="left"] img {
width: 100%;
height: 100%;
min-width: 0;
object-fit: contain;
}
& > [data-slot="right"] img {
width: 100%;
height: calc(100% - 2rem);
object-fit: contain;
display: block;
}
@media (max-width: 30rem) {
& {
--images-height: auto;
grid-template-columns: 1fr;
grid-template-rows: auto auto;
}
& > [data-slot="left"] {
grid-row: 1;
grid-column: 1;
}
& > [data-slot="right"] {
grid-row: 2;
grid-column: 1;
border-left: none;
border-top: 1px solid var(--color-border);
& > [data-slot="row1"],
& > [data-slot="row2"] {
height: auto;
}
}
& > [data-slot="left"] figure,
& > [data-slot="right"] figure {
height: auto;
}
& > [data-slot="left"] img,
& > [data-slot="right"] img {
width: 100%;
height: auto;
max-height: none;
}
}
}
[data-component="copy-status"] {
@media (max-width: 38rem) {
display: none;
}
[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: var(--color-text);
[data-copied] & {
display: block;
}
}
}
[data-component="footer"] {
border-top: 1px solid var(--color-border);
display: flex;
flex-direction: row;
[data-slot="cell"] {
flex: 1;
text-align: center;
text-transform: uppercase;
padding: var(--vertical-padding) 0.5rem;
}
[data-slot="cell"] + [data-slot="cell"] {
border-left: 1px solid var(--color-border);
}
/* Mobile: third column on its own row */
@media (max-width: 30rem) {
flex-wrap: wrap;
[data-slot="cell"]:nth-child(1),
[data-slot="cell"]:nth-child(2) {
flex: 1;
}
[data-slot="cell"]:nth-child(3) {
flex: 1 0 100%;
border-left: none;
border-top: 1px solid var(--color-border);
}
}
}
[data-component="legal"] {
color: var(--color-text-dimmed);
text-align: center;
a {
color: var(--color-text-dimmed);
}
}
}
+183
View File
@@ -0,0 +1,183 @@
import "./index.css"
import { Title } from "@solidjs/meta"
import { onCleanup, onMount } from "solid-js"
import logoLight from "../asset/logo-ornate-light.svg"
import logoDark from "../asset/logo-ornate-dark.svg"
import IMG_SPLASH from "../asset/lander/screenshot-splash.png"
import { IconCopy, IconCheck } from "../component/icon"
import { createAsync, query } from "@solidjs/router"
import { getActor } from "~/context/auth"
import { withActor } from "~/context/auth.withActor"
import { Account } from "@opencode/cloud-core/account.js"
function CopyStatus() {
return (
<div data-component="copy-status">
<IconCopy data-slot="copy" />
<IconCheck data-slot="check" />
</div>
)
}
const defaultWorkspace = query(async () => {
"use server"
const actor = await getActor()
if (actor.type === "account") {
const workspaces = await withActor(() => Account.workspaces())
return workspaces[0].id
}
}, "defaultWorkspace")
export default function Home() {
const workspace = createAsync(() => defaultWorkspace())
onMount(() => {
const commands = document.querySelectorAll("[data-copy]")
for (const button of commands) {
const callback = () => {
const text = button.textContent
if (text) {
navigator.clipboard.writeText(text)
button.setAttribute("data-copied", "")
setTimeout(() => {
button.removeAttribute("data-copied")
}, 1500)
}
}
button.addEventListener("click", callback)
onCleanup(() => {
button.removeEventListener("click", callback)
})
}
})
return (
<main data-page="home">
<Title>opencode | AI coding agent built for the terminal</Title>
<div data-component="content">
<section data-component="top">
<img data-slot="logo light" src={logoLight} alt="opencode logo light" />
<img data-slot="logo dark" src={logoDark} alt="opencode logo dark" />
<h1 data-slot="title">The AI coding agent built for the terminal</h1>
<div data-slot="login">
<a href="/auth">opencode zen</a>
</div>
</section>
<section data-component="cta">
<div data-slot="left">
<a href="/docs">Get Started</a>
</div>
<div data-slot="center">
<a href="/auth">opencode zen</a>
</div>
<div data-slot="right">
<button data-copy data-slot="command">
<span>
<span>curl -fsSL </span>
<span data-slot="protocol">https://</span>
<span data-slot="highlight">opencode.ai/install</span>
<span> | bash</span>
</span>
<CopyStatus />
</button>
</div>
</section>
<section data-component="features">
<ul data-slot="list">
<li>
<strong>Native TUI</strong> A responsive, native, themeable terminal UI
</li>
<li>
<strong>LSP enabled</strong> Automatically loads the right LSPs for the LLM
</li>
<li>
<strong>opencode zen</strong> A <a href="/docs/zen">curated list of models</a> provided by opencode{" "}
<label>New</label>
</li>
<li>
<strong>Multi-session</strong> Start multiple agents in parallel on the same project
</li>
<li>
<strong>Shareable links</strong> Share a link to any sessions for reference or to debug
</li>
<li>
<strong>Claude Pro</strong> Log in with Anthropic to use your Claude Pro or Max account
</li>
<li>
<strong>Use any model</strong> Supports 75+ LLM providers through{" "}
<a href="https://models.dev">Models.dev</a>, including local models
</li>
</ul>
</section>
<section data-component="install">
<div data-component="method">
<h3 data-component="title">npm</h3>
<button data-copy data-slot="button">
<span>
npm install -g <strong>opencode-ai</strong>
</span>
<CopyStatus />
</button>
</div>
<div data-component="method">
<h3 data-component="title">bun</h3>
<button data-copy data-slot="button">
<span>
bun install -g <strong>opencode-ai</strong>
</span>
<CopyStatus />
</button>
</div>
<div data-component="method">
<h3 data-component="title">homebrew</h3>
<button data-copy data-slot="button">
<span>
brew install <strong>sst/tap/opencode</strong>
</span>
<CopyStatus />
</button>
</div>
<div data-component="method">
<h3 data-component="title">paru</h3>
<button data-copy data-slot="button">
<span>
paru -S <strong>opencode-bin</strong>
</span>
<CopyStatus />
</button>
</div>
</section>
<section data-component="screenshots">
<figure>
<figcaption>opencode TUI with the tokyonight theme</figcaption>
<a href="/docs/cli">
<img src={IMG_SPLASH} alt="opencode TUI with tokyonight theme" />
</a>
</figure>
</section>
<footer data-component="footer">
<div data-slot="cell">
<a href="https://x.com/opencode">X.com</a>
</div>
<div data-slot="cell">
<a href="https://github.com/sst/opencode">GitHub</a>
</div>
<div data-slot="cell">
<a href="https://opencode.ai/discord">Discord</a>
</div>
</footer>
</div>
<div data-component="legal">
<span>
©2025 <a href="https://anoma.ly">Anomaly Innovations</a>
</span>
</div>
</main>
)
}
+20
View File
@@ -0,0 +1,20 @@
import type { APIEvent } from "@solidjs/start/server"
async function handler(evt: APIEvent) {
const req = evt.request.clone()
const url = new URL(req.url)
const targetUrl = `https://docs.opencode.ai/docs${url.pathname}${url.search}`
const response = await fetch(targetUrl, {
method: req.method,
headers: req.headers,
body: req.body,
})
return response
}
export const GET = handler
export const POST = handler
export const PUT = handler
export const DELETE = handler
export const OPTIONS = handler
export const PATCH = handler
+75
View File
@@ -0,0 +1,75 @@
import { Billing } from "@opencode/cloud-core/billing.js"
import type { APIEvent } from "@solidjs/start/server"
import { Database, eq, sql } from "@opencode/cloud-core/drizzle/index.js"
import { BillingTable, PaymentTable } from "@opencode/cloud-core/schema/billing.sql.js"
import { Identifier } from "@opencode/cloud-core/identifier.js"
import { centsToMicroCents } from "@opencode/cloud-core/util/price.js"
import { Actor } from "@opencode/cloud-core/actor.js"
import { Resource } from "@opencode/cloud-resource"
export async function POST(input: APIEvent) {
const body = await Billing.stripe().webhooks.constructEventAsync(
await input.request.text(),
input.request.headers.get("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")
const chargedAmount = 2000
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(chargedAmount)}`,
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(chargedAmount),
paymentID,
customerID,
})
})
})
}
console.log("finished handling")
return Response.json("ok", { status: 200 })
}
+127
View File
@@ -0,0 +1,127 @@
[data-page="workspace"] {
line-height: 1;
/* Common elements */
button {
padding: var(--space-3) var(--space-4);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-sm);
background-color: var(--color-bg);
color: var(--color-text);
font-size: var(--font-size-sm);
font-family: var(--font-sans);
font-weight: 500;
text-transform: uppercase;
cursor: pointer;
transition: all 0.15s ease;
&:hover:not(:disabled) {
background-color: var(--color-surface-hover);
border-color: var(--color-accent);
}
&:active {
transform: translateY(1px);
}
&:disabled {
opacity: 0.5;
transform: none;
}
&[data-color="primary"] {
background-color: var(--color-primary);
border-color: var(--color-primary);
color: var(--color-primary-text);
&:hover:not(:disabled) {
background-color: var(--color-primary-hover);
border-color: var(--color-primary-hover);
}
}
&[data-color="ghost"] {
background-color: transparent;
border-color: transparent;
color: var(--color-text-muted);
&:hover:not(:disabled) {
background-color: var(--color-surface-hover);
border-color: var(--color-border);
color: var(--color-text);
}
}
}
a {
color: var(--color-text);
text-decoration: underline;
text-underline-offset: var(--space-0-75);
text-decoration-thickness: 1px;
}
/* Workspace Header */
[data-component="workspace-header"] {
position: sticky;
top: 0;
z-index: 100;
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--space-4) var(--space-4);
border-bottom: 1px solid var(--color-border);
background-color: var(--color-bg);
@media (max-width: 30rem) {
padding: var(--space-4) var(--space-4);
}
}
[data-slot="header-brand"] {
flex: 0 0 auto;
padding-top: 4px;
svg {
width: 138px;
}
[data-component="site-title"] {
font-size: var(--font-size-lg);
font-weight: 600;
color: var(--color-text);
text-decoration: none;
letter-spacing: -0.02em;
}
}
[data-slot="header-actions"] {
display: flex;
gap: var(--space-4);
align-items: center;
font-size: var(--font-size-sm);
[data-slot="user"] {
color: var(--color-text-muted);
}
@media (max-width: 30rem) {
[data-slot="user"] {
display: none;
}
}
a,
button {
appearance: none;
background: none;
border: none;
cursor: pointer;
padding: 0;
color: var(--color-text);
text-decoration: underline;
text-underline-offset: var(--space-0-75);
text-decoration-thickness: 1px;
text-transform: uppercase;
}
}
}
+67
View File
@@ -0,0 +1,67 @@
import "./workspace.css"
import { useAuthSession } from "~/context/auth.session"
import { IconLogo } from "../component/icon"
import { withActor } from "~/context/auth.withActor"
import {
query,
action,
redirect,
createAsync,
RouteSectionProps,
Navigate,
useNavigate,
useParams,
A,
} from "@solidjs/router"
import { User } from "@opencode/cloud-core/user.js"
import { Actor } from "@opencode/cloud-core/actor.js"
import { getRequestEvent } from "solid-js/web"
const getUserInfo = query(async (workspaceID: string) => {
"use server"
return withActor(async () => {
const actor = Actor.assert("user")
return await User.fromID(actor.properties.userID)
}, workspaceID)
}, "userInfo")
const logout = action(async () => {
"use server"
const auth = await useAuthSession()
const event = getRequestEvent()
const current = auth.data.current
if (current)
await auth.update((val) => {
delete val.account?.[current]
const first = Object.keys(val.account ?? {})[0]
val.current = first
event!.locals.actor = undefined
return val
})
throw redirect("/")
})
export default function WorkspaceLayout(props: RouteSectionProps) {
const params = useParams()
const userInfo = createAsync(() => getUserInfo(params.id))
return (
<main data-page="workspace">
<header data-component="workspace-header">
<div data-slot="header-brand">
<A href="/" data-component="site-title">
<IconLogo />
</A>
</div>
<div data-slot="header-actions">
<span data-slot="user">{userInfo()?.email}</span>
<form action={logout} method="post">
<button type="submit" formaction={logout}>
Logout
</button>
</form>
</div>
</header>
<div>{props.children}</div>
</main>
)
}
+634
View File
@@ -0,0 +1,634 @@
[data-page="workspace-[id]"] {
max-width: 64rem;
padding: var(--space-10) var(--space-4);
margin: 0 auto;
width: 100%;
display: flex;
flex-direction: column;
gap: var(--space-10);
@media (max-width: 30rem) {
padding-top: var(--space-4);
padding-bottom: var(--space-4);
gap: var(--space-8);
}
[data-slot="sections"] {
display: flex;
flex-direction: column;
gap: var(--space-16);
@media (max-width: 30rem) {
gap: var(--space-8);
}
section {
display: flex;
flex-direction: column;
gap: var(--space-6);
/* Section titles */
[data-slot="section-title"] {
display: flex;
flex-direction: column;
gap: var(--space-1);
h2 {
font-size: var(--font-size-md);
font-weight: 600;
line-height: 1.2;
letter-spacing: -0.03125rem;
margin: 0;
color: var(--color-text-secondary);
text-transform: uppercase;
@media (max-width: 30rem) {
font-size: var(--font-size-md);
}
}
}
}
section:not(:last-child) {
border-bottom: 1px solid var(--color-border);
padding-bottom: var(--space-16);
@media (max-width: 30rem) {
padding-bottom: var(--space-8);
}
}
}
[data-component="empty-state"] {
padding: var(--space-20) var(--space-6);
text-align: center;
border: 1px dashed var(--color-border);
border-radius: var(--border-radius-sm);
display: flex;
flex-direction: column;
gap: var(--space-2);
p {
line-height: 1.5;
font-size: var(--font-size-sm);
color: var(--color-text-muted);
}
}
/* Title section */
[data-component="title-section"] {
display: flex;
flex-direction: column;
gap: var(--space-2);
padding-bottom: var(--space-8);
border-bottom: 1px solid var(--color-border);
@media (max-width: 30rem) {
padding-bottom: var(--space-6);
}
h1 {
font-size: var(--font-size-2xl);
font-weight: 500;
line-height: 1.2;
letter-spacing: -0.03125rem;
margin: 0;
text-transform: uppercase;
@media (max-width: 30rem) {
font-size: var(--font-size-xl);
}
}
p {
line-height: 1.5;
font-size: var(--font-size-md);
color: var(--color-text-muted);
a {
color: var(--color-text-muted);
}
}
}
/* API Keys Section */
[data-component="api-keys-section"] {
[data-slot="create-form"] {
display: flex;
gap: var(--space-3);
padding: var(--space-4);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-sm);
@media (max-width: 30rem) {
gap: var(--space-2);
}
input {
flex: 1;
padding: var(--space-2) var(--space-3);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-sm);
background-color: var(--color-bg);
color: var(--color-text);
font-size: var(--font-size-sm);
font-family: var(--font-mono);
&:focus {
outline: none;
border-color: var(--color-accent);
}
&::placeholder {
color: var(--color-text-disabled);
}
}
[data-slot="form-actions"] {
display: flex;
gap: var(--space-2);
}
}
[data-slot="api-keys-table"] {
overflow-x: auto;
}
[data-slot="api-keys-table-element"] {
width: 100%;
border-collapse: collapse;
font-size: var(--font-size-sm);
thead {
border-bottom: 1px solid var(--color-border);
}
th {
padding: var(--space-3) var(--space-4);
text-align: left;
font-weight: normal;
color: var(--color-text-muted);
text-transform: uppercase;
}
td {
padding: var(--space-3) var(--space-4);
border-bottom: 1px solid var(--color-border-muted);
color: var(--color-text-muted);
font-family: var(--font-mono);
&[data-slot="key-name"] {
color: var(--color-text);
font-family: var(--font-sans);
font-weight: 500;
}
&[data-slot="key-value"] {
font-family: var(--font-mono);
button {
display: flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-2) var(--space-3);
font-size: var(--font-size-sm);
font-weight: 400;
border: none;
background-color: transparent;
color: var(--color-text-muted);
font-family: var(--font-mono);
border-radius: var(--border-radius-sm);
cursor: pointer;
transition: all 0.15s ease;
text-transform: none;
&:hover:not(:disabled) {
background-color: var(--color-bg-surface);
color: var(--color-text);
}
&:disabled {
cursor: default;
color: var(--color-text);
}
span {
font-family: inherit;
}
}
}
&[data-slot="key-date"] {
color: var(--color-text);
}
&[data-slot="key-actions"] {
font-family: var(--font-sans);
}
}
tbody tr {
&:last-child td {
border-bottom: none;
}
}
@media (max-width: 40rem) {
th,
td {
padding: var(--space-2) var(--space-3);
font-size: var(--font-size-xs);
}
th {
&:nth-child(3) /* Date */ {
display: none;
}
}
td {
&:nth-child(3) /* Date */ {
display: none;
}
}
}
}
}
/* Balance Section */
[data-component="balance-section"] {
[data-slot="balance"] {
display: flex;
flex-direction: column;
gap: var(--space-3);
padding: var(--space-4);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-sm);
min-width: 14.5rem;
width: fit-content;
[data-slot="amount"] {
padding: var(--space-3-5) var(--space-4);
background-color: var(--color-bg-surface);
border-radius: var(--border-radius-sm);
display: flex;
align-items: baseline;
gap: var(--space-1);
justify-content: flex-end;
&[data-state="danger"] {
[data-slot="value"] {
color: var(--color-danger);
}
[data-slot="currency"] {
color: var(--color-danger);
}
}
[data-slot="currency"] {
position: relative;
bottom: 2px;
font-size: var(--font-size-lg);
color: var(--color-text-muted);
font-weight: 400;
}
[data-slot="value"] {
font-size: var(--font-size-3xl);
font-weight: 500;
color: var(--color-text);
}
}
}
}
/* Payments Section */
[data-component="payments-section"] {
[data-slot="payments-table"] {
overflow-x: auto;
}
[data-slot="payments-table-element"] {
width: 100%;
border-collapse: collapse;
font-size: var(--font-size-sm);
thead {
border-bottom: 1px solid var(--color-border);
}
th {
padding: var(--space-3) var(--space-4);
text-align: left;
font-weight: normal;
color: var(--color-text-muted);
text-transform: uppercase;
}
td {
padding: var(--space-3) var(--space-4);
border-bottom: 1px solid var(--color-border-muted);
color: var(--color-text-muted);
font-family: var(--font-mono);
&[data-slot="payment-date"] {
color: var(--color-text);
}
&[data-slot="payment-id"] {
font-family: var(--font-mono);
font-weight: 400;
color: var(--color-text-muted);
max-width: 200px;
word-break: break-word;
}
&[data-slot="payment-amount"] {
color: var(--color-text);
}
}
tbody tr {
&:last-child td {
border-bottom: none;
}
}
@media (max-width: 40rem) {
th,
td {
padding: var(--space-2) var(--space-3);
font-size: var(--font-size-xs);
}
th {
&:nth-child(2) /* Payment ID */ {
display: none;
}
}
td {
&:nth-child(2) /* Payment ID */ {
display: none;
}
}
}
}
}
/* Usage Section */
[data-component="usage-section"] {
[data-slot="usage-table"] {
overflow-x: auto;
}
[data-slot="usage-table-element"] {
width: 100%;
border-collapse: collapse;
font-size: var(--font-size-sm);
thead {
border-bottom: 1px solid var(--color-border);
}
th {
padding: var(--space-3) var(--space-4);
text-align: left;
font-weight: normal;
color: var(--color-text-muted);
text-transform: uppercase;
}
td {
padding: var(--space-3) var(--space-4);
border-bottom: 1px solid var(--color-border-muted);
color: var(--color-text-muted);
font-family: var(--font-mono);
&[data-slot="usage-date"] {
color: var(--color-text);
}
&[data-slot="usage-model"] {
font-family: var(--font-sans);
font-weight: 400;
color: var(--color-text-secondary);
max-width: 200px;
word-break: break-word;
}
&[data-slot="usage-cost"] {
color: var(--color-text);
}
}
tbody tr {
&:last-child td {
border-bottom: none;
}
}
@media (max-width: 40rem) {
th,
td {
padding: var(--space-2) var(--space-3);
font-size: var(--font-size-xs);
}
th {
&:nth-child(2) /* Model */ {
display: none;
}
}
td {
&:nth-child(2) /* Model */ {
display: none;
}
}
}
}
}
[data-slot="new-user-sections"] {
display: flex;
flex-direction: column;
gap: var(--space-16);
@media (max-width: 30rem) {
gap: var(--space-8);
}
[data-component="feature-grid"] {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: var(--space-6);
@media (max-width: 30rem) {
grid-template-columns: 1fr;
gap: var(--space-4);
}
[data-slot="feature"] {
display: flex;
flex-direction: column;
gap: var(--space-2);
padding: var(--space-4);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-sm);
background-color: var(--color-bg-surface);
h3 {
font-size: var(--font-size-sm);
font-weight: 600;
margin: 0;
color: var(--color-text);
text-transform: uppercase;
letter-spacing: -0.025rem;
}
p {
font-size: var(--font-size-sm);
line-height: 1.5;
margin: 0;
color: var(--color-text-muted);
}
}
}
[data-component="api-key-highlight"] {
display: flex;
flex-direction: column;
gap: var(--space-6);
[data-slot="section-title"] {
display: flex;
flex-direction: column;
gap: var(--space-1);
h2 {
font-size: var(--font-size-md);
font-weight: 600;
line-height: 1.2;
letter-spacing: -0.03125rem;
margin: 0;
color: var(--color-text-secondary);
text-transform: uppercase;
@media (max-width: 30rem) {
font-size: var(--font-size-md);
}
}
}
[data-slot="key-display"] {
display: flex;
flex-direction: column;
gap: var(--space-3);
[data-slot="key-container"] {
display: flex;
gap: var(--space-3);
padding: var(--space-4);
border: 2px solid var(--color-accent);
border-radius: var(--border-radius-sm);
background-color: var(--color-bg-surface);
align-items: center;
@media (max-width: 40rem) {
flex-direction: column;
gap: var(--space-3);
align-items: stretch;
}
[data-slot="key-value"] {
flex: 1;
font-family: var(--font-mono);
font-size: var(--font-size-sm);
color: var(--color-text);
background-color: var(--color-bg);
padding: var(--space-3);
border-radius: var(--border-radius-sm);
border: 1px solid var(--color-border);
word-break: break-all;
line-height: 1.4;
@media (max-width: 40rem) {
font-size: var(--font-size-xs);
padding: var(--space-2-5);
}
}
button {
display: flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-3) var(--space-4);
font-size: var(--font-size-sm);
font-weight: 500;
white-space: nowrap;
min-width: 130px;
@media (max-width: 40rem) {
justify-content: center;
padding: var(--space-2-5) var(--space-3);
font-size: var(--font-size-xs);
min-width: 96px;
}
}
}
}
}
[data-component="next-steps"] {
display: flex;
flex-direction: column;
gap: var(--space-6);
[data-slot="section-title"] {
display: flex;
flex-direction: column;
gap: var(--space-1);
h2 {
font-size: var(--font-size-md);
font-weight: 600;
line-height: 1.2;
letter-spacing: -0.03125rem;
margin: 0;
color: var(--color-text-secondary);
text-transform: uppercase;
@media (max-width: 30rem) {
font-size: var(--font-size-md);
}
}
}
ol {
margin: 0;
padding-left: 0;
display: flex;
flex-direction: column;
gap: var(--space-2);
list-style-position: inside;
li {
font-size: var(--font-size-sm);
line-height: 1.5;
color: var(--color-text-muted);
code {
font-family: var(--font-mono);
font-size: var(--font-size-xs);
padding: var(--space-1) var(--space-2);
background-color: var(--color-bg-surface);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-sm);
color: var(--color-text);
}
}
}
}
}
}
+486
View File
@@ -0,0 +1,486 @@
import "./[id].css"
import { Billing } from "@opencode/cloud-core/billing.js"
import { Key } from "@opencode/cloud-core/key.js"
import { json, query, action, useParams, useAction, createAsync, useSubmission } from "@solidjs/router"
import { createEffect, createMemo, createSignal, For, Show } from "solid-js"
import { withActor } from "~/context/auth.withActor"
import { IconCopy, IconCheck } from "~/component/icon"
import { createStore } from "solid-js/store"
function formatDateForTable(date: Date) {
const options: Intl.DateTimeFormatOptions = {
day: "numeric",
month: "short",
hour: "numeric",
minute: "2-digit",
hour12: true,
}
return date.toLocaleDateString("en-GB", options).replace(",", ",")
}
function formatDateUTC(date: Date) {
const options: Intl.DateTimeFormatOptions = {
weekday: "short",
year: "numeric",
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
second: "2-digit",
timeZoneName: "short",
timeZone: "UTC",
}
return date.toLocaleDateString("en-US", options)
}
/////////////////////////////////////
// Keys related queries and actions
/////////////////////////////////////
const listKeys = query(async (workspaceID: string) => {
"use server"
return withActor(() => Key.list(), workspaceID)
}, "key.list")
const createKey = action(async (form: FormData) => {
"use server"
const name = form.get("name")?.toString().trim()
if (!name) return { error: "Name is required" }
const workspaceID = form.get("workspaceID")?.toString()
if (!workspaceID) return { error: "Workspace ID is required" }
return json(
withActor(() => Key.create({ name }), workspaceID),
{ revalidate: listKeys.key },
)
}, "key.create")
const removeKey = action(async (form: FormData) => {
"use server"
const id = form.get("id")?.toString()
if (!id) return { error: "ID is required" }
const workspaceID = form.get("workspaceID")?.toString()
if (!workspaceID) return { error: "Workspace ID is required" }
return json(
withActor(() => Key.remove({ id }), workspaceID),
{ revalidate: listKeys.key },
)
}, "key.remove")
/////////////////////////////////////
// Billing related queries and actions
/////////////////////////////////////
const getBalanceInfo = query(async (workspaceID: string) => {
"use server"
return withActor(async () => {
return await Billing.get()
}, workspaceID)
}, "balanceInfo")
const getUsageInfo = query(async (workspaceID: string) => {
"use server"
return withActor(async () => {
return await Billing.usages()
}, workspaceID)
}, "usageInfo")
const getPaymentsInfo = query(async (workspaceID: string) => {
"use server"
return withActor(async () => {
return await Billing.payments()
}, workspaceID)
}, "paymentsInfo")
const createCheckoutUrl = action(async (workspaceID: string, successUrl: string, cancelUrl: string) => {
"use server"
return withActor(() => Billing.generateCheckoutUrl({ successUrl, cancelUrl }), workspaceID)
}, "checkoutUrl")
// const createPortalUrl = action(async (workspaceID: string, returnUrl: string) => {
// "use server"
// return withActor(() => Billing.generatePortalUrl({ returnUrl }), workspaceID)
// }, "portalUrl")
function KeySection() {
const params = useParams()
const keys = createAsync(() => listKeys(params.id))
function formatKey(key: string) {
if (key.length <= 11) return key
return `${key.slice(0, 7)}...${key.slice(-4)}`
}
return (
<section data-component="api-keys-section">
<div data-slot="section-title">
<h2>API Keys</h2>
<p>Manage your API keys for accessing opencode services.</p>
</div>
<KeyCreateForm />
<div data-slot="api-keys-table">
<Show
when={keys()?.length}
fallback={
<div data-component="empty-state">
<p>Create an opencode Gateway API key</p>
</div>
}
>
<table data-slot="api-keys-table-element">
<thead>
<tr>
<th>Name</th>
<th>Key</th>
<th>Created</th>
<th></th>
</tr>
</thead>
<tbody>
<For each={keys()!}>
{(key) => {
const [copied, setCopied] = createSignal(false)
// const submission = useSubmission(removeKey, ([fd]) => fd.get("id")?.toString() === key.id)
return (
<tr>
<td data-slot="key-name">{key.name}</td>
<td data-slot="key-value">
<button
data-color="ghost"
disabled={copied()}
onClick={async () => {
await navigator.clipboard.writeText(key.key)
setCopied(true)
setTimeout(() => setCopied(false), 1000)
}}
title="Copy API key"
>
<span>{formatKey(key.key)}</span>
<Show when={copied()} fallback={<IconCopy style={{ width: "14px", height: "14px" }} />}>
<IconCheck style={{ width: "14px", height: "14px" }} />
</Show>
</button>
</td>
<td data-slot="key-date" title={formatDateUTC(key.timeCreated)}>
{formatDateForTable(key.timeCreated)}
</td>
<td data-slot="key-actions">
<form action={removeKey} method="post">
<input type="hidden" name="id" value={key.id} />
<input type="hidden" name="workspaceID" value={params.id} />
<button data-color="ghost">Delete</button>
</form>
</td>
</tr>
)
}}
</For>
</tbody>
</table>
</Show>
</div>
</section>
)
}
function KeyCreateForm() {
const params = useParams()
const submission = useSubmission(createKey)
const [store, setStore] = createStore({
show: false,
})
let input: HTMLInputElement
createEffect(() => {
if (!submission.pending && submission.result) {
hide()
}
})
function show() {
setStore("show", true)
input.focus()
}
function hide() {
setStore("show", false)
}
return (
<Show
when={store.show}
fallback={
<button data-color="primary" onClick={() => show()}>
Create API Key
</button>
}
>
<form action={createKey} method="post" data-slot="create-form">
<input ref={(r) => (input = r)} data-component="input" name="name" type="text" placeholder="Enter key name" />
<input type="hidden" name="workspaceID" value={params.id} />
<div data-slot="form-actions">
<button type="reset" data-color="ghost" onClick={() => hide()}>
Cancel
</button>
<button type="submit" data-color="primary" disabled={submission.pending}>
{submission.pending ? "Creating..." : "Create"}
</button>
</div>
</form>
</Show>
)
}
function BalanceSection() {
const params = useParams()
const balanceInfo = createAsync(() => getBalanceInfo(params.id))
const createCheckoutUrlAction = useAction(createCheckoutUrl)
const createCheckoutUrlSubmission = useSubmission(createCheckoutUrl)
return (
<section data-component="balance-section">
<div data-slot="section-title">
<h2>Balance</h2>
<p>Add credits to your account.</p>
</div>
<div data-slot="balance">
<div
data-slot="amount"
data-state={(() => {
const balanceStr = ((balanceInfo()?.balance ?? 0) / 100000000).toFixed(2)
return balanceStr === "0.00" || balanceStr === "-0.00" ? "danger" : undefined
})()}
>
<span data-slot="currency">$</span>
<span data-slot="value">
{(() => {
const balanceStr = ((balanceInfo()?.balance ?? 0) / 100000000).toFixed(2)
return balanceStr === "-0.00" ? "0.00" : balanceStr
})()}
</span>
</div>
<button
data-color="primary"
disabled={createCheckoutUrlSubmission.pending}
onClick={async () => {
const baseUrl = window.location.href
const checkoutUrl = await createCheckoutUrlAction(params.id, baseUrl, baseUrl)
if (checkoutUrl) {
window.location.href = checkoutUrl
}
}}
>
{createCheckoutUrlSubmission.pending ? "Loading..." : "Buy Credits"}
</button>
</div>
</section>
)
}
function UsageSection() {
const params = useParams()
const usage = createAsync(() => getUsageInfo(params.id))
return (
<section data-component="usage-section">
<div data-slot="section-title">
<h2>Usage History</h2>
<p>Recent API usage and costs.</p>
</div>
<div data-slot="usage-table">
<Show
when={usage() && usage()!.length > 0}
fallback={
<div data-component="empty-state">
<p>Make your first API call to get started.</p>
</div>
}
>
<table data-slot="usage-table-element">
<thead>
<tr>
<th>Date</th>
<th>Model</th>
<th>Input</th>
<th>Output</th>
<th>Cost</th>
</tr>
</thead>
<tbody>
<For each={usage()!}>
{(usage) => {
const date = createMemo(() => new Date(usage.timeCreated))
return (
<tr>
<td data-slot="usage-date" title={formatDateUTC(date())}>
{formatDateForTable(date())}
</td>
<td data-slot="usage-model">{usage.model}</td>
<td data-slot="usage-tokens">{usage.inputTokens}</td>
<td data-slot="usage-tokens">{usage.outputTokens}</td>
<td data-slot="usage-cost">${((usage.cost ?? 0) / 100000000).toFixed(4)}</td>
</tr>
)
}}
</For>
</tbody>
</table>
</Show>
</div>
</section>
)
}
function PaymentSection() {
const params = useParams()
const payments = createAsync(() => getPaymentsInfo(params.id))
return (
payments() &&
payments()!.length > 0 && (
<section data-component="payments-section">
<div data-slot="section-title">
<h2>Payments History</h2>
<p>Recent payment transactions.</p>
</div>
<div data-slot="payments-table">
<table data-slot="payments-table-element">
<thead>
<tr>
<th>Date</th>
<th>Payment ID</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<For each={payments()!}>
{(payment) => {
const date = new Date(payment.timeCreated)
return (
<tr>
<td data-slot="payment-date" title={formatDateUTC(date)}>
{formatDateForTable(date)}
</td>
<td data-slot="payment-id">{payment.id}</td>
<td data-slot="payment-amount">${((payment.amount ?? 0) / 100000000).toFixed(2)}</td>
</tr>
)
}}
</For>
</tbody>
</table>
</div>
</section>
)
)
}
function NewUserSection() {
const params = useParams()
const [copiedKey, setCopiedKey] = createSignal(false)
const keys = createAsync(() => listKeys(params.id))
const usage = createAsync(() => getUsageInfo(params.id))
const isNew = createMemo(() => {
const keysList = keys()
const usageList = usage()
return keysList?.length === 1 && (!usageList || usageList.length === 0)
})
const defaultKey = createMemo(() => keys()?.at(-1)?.key)
return (
<Show when={isNew()}>
<div data-slot="new-user-sections">
<div data-component="feature-grid">
<div data-slot="feature">
<h3>Tested & Verified Models</h3>
<p>We've benchmarked and tested models specifically for coding agents to ensure the best performance.</p>
</div>
<div data-slot="feature">
<h3>Highest Quality</h3>
<p>Access models configured for optimal performance - no downgrades or routing to cheaper providers.</p>
</div>
<div data-slot="feature">
<h3>No Lock-in</h3>
<p>Use Zen with any coding agent, and continue using other providers with opencode whenever you want.</p>
</div>
</div>
<div data-component="api-key-highlight">
<div data-slot="section-title">
<h2>Your API Key</h2>
</div>
<Show when={defaultKey()}>
<div data-slot="key-display">
<div data-slot="key-container">
<code data-slot="key-value">{defaultKey()}</code>
<button
data-color="primary"
disabled={copiedKey()}
onClick={async () => {
await navigator.clipboard.writeText(defaultKey() ?? "")
setCopiedKey(true)
setTimeout(() => setCopiedKey(false), 2000)
}}
title="Copy API key"
>
<Show
when={copiedKey()}
fallback={
<>
<IconCopy style={{ width: "16px", height: "16px" }} /> Copy Key
</>
}
>
<IconCheck style={{ width: "16px", height: "16px" }} /> Copied!
</Show>
</button>
</div>
</div>
</Show>
</div>
<div data-component="next-steps">
<div data-slot="section-title">
<h2>Next Steps</h2>
</div>
<ol>
<li>Copy your API key above</li>
<li>
Run <code>opencode auth login</code> and select opencode
</li>
<li>Paste your API key when prompted</li>
<li>
Run <code>/models</code> to see available models
</li>
</ol>
</div>
</div>
</Show>
)
}
export default function () {
return (
<div data-page="workspace-[id]">
<section data-component="title-section">
<h1>Zen</h1>
<p>
Curated list of models provided by opencode.{" "}
<a target="_blank" href="/docs/zen">
Learn more
</a>
.
</p>
</section>
<div data-slot="sections">
<NewUserSection />
<KeySection />
<BalanceSection />
<UsageSection />
<PaymentSection />
</div>
</div>
)
}
@@ -0,0 +1,54 @@
import type { APIEvent } from "@solidjs/start/server"
import { handler } from "~/util/zen"
type Usage = {
prompt_tokens?: number
completion_tokens?: number
total_tokens?: number
prompt_tokens_details?: {
text_tokens?: number
audio_tokens?: number
image_tokens?: number
cached_tokens?: number
}
completion_tokens_details?: {
reasoning_tokens?: number
audio_tokens?: number
accepted_prediction_tokens?: number
rejected_prediction_tokens?: number
}
}
export function POST(input: APIEvent) {
let usage: Usage
return handler(input, {
modifyBody: (body: any) => ({
...body,
...(body.stream ? { stream_options: { include_usage: true } } : {}),
}),
setAuthHeader: (headers: Headers, apiKey: string) => {
headers.set("authorization", `Bearer ${apiKey}`)
},
parseApiKey: (headers: Headers) => headers.get("authorization")?.split(" ")[1],
onStreamPart: (chunk: string) => {
if (!chunk.startsWith("data: ")) return
let json
try {
json = JSON.parse(chunk.slice(6)) as { usage?: Usage }
} catch (e) {
return
}
if (!json.usage) return
usage = json.usage
},
getStreamUsage: () => usage,
normalizeUsage: (usage: Usage) => ({
inputTokens: usage.prompt_tokens ?? 0,
outputTokens: usage.completion_tokens ?? 0,
reasoningTokens: usage.completion_tokens_details?.reasoning_tokens ?? undefined,
cacheReadTokens: usage.prompt_tokens_details?.cached_tokens ?? undefined,
}),
})
}
+61
View File
@@ -0,0 +1,61 @@
import type { APIEvent } from "@solidjs/start/server"
import { handler } from "~/util/zen"
type Usage = {
cache_creation?: {
ephemeral_5m_input_tokens?: number
ephemeral_1h_input_tokens?: number
}
cache_creation_input_tokens?: number
cache_read_input_tokens?: number
input_tokens?: number
output_tokens?: number
server_tool_use?: {
web_search_requests?: number
}
}
export function POST(input: APIEvent) {
let usage: Usage
return handler(input, {
modifyBody: (body: any) => ({
...body,
service_tier: "standard_only",
}),
setAuthHeader: (headers: Headers, apiKey: string) => headers.set("x-api-key", apiKey),
parseApiKey: (headers: Headers) => headers.get("x-api-key") ?? undefined,
onStreamPart: (chunk: string) => {
const data = chunk.split("\n")[1]
if (!data.startsWith("data: ")) return
let json
try {
json = JSON.parse(data.slice(6)) as { usage?: Usage }
} catch (e) {
return
}
if (!json.usage) return
usage = {
...usage,
...json.usage,
cache_creation: {
...usage?.cache_creation,
...json.usage.cache_creation,
},
server_tool_use: {
...usage?.server_tool_use,
...json.usage.server_tool_use,
},
}
},
getStreamUsage: () => usage,
normalizeUsage: (usage: Usage) => ({
inputTokens: usage.input_tokens ?? 0,
outputTokens: usage.output_tokens ?? 0,
cacheReadTokens: usage.cache_read_input_tokens ?? undefined,
cacheWrite5mTokens: usage.cache_creation?.ephemeral_5m_input_tokens ?? undefined,
cacheWrite1hTokens: usage.cache_creation?.ephemeral_1h_input_tokens ?? undefined,
}),
})
}
+52
View File
@@ -0,0 +1,52 @@
import type { APIEvent } from "@solidjs/start/server"
import { handler } from "~/util/zen"
type Usage = {
input_tokens?: number
input_tokens_details?: {
cached_tokens?: number
}
output_tokens?: number
output_tokens_details?: {
reasoning_tokens?: number
}
total_tokens?: number
}
export function POST(input: APIEvent) {
let usage: Usage
return handler(input, {
setAuthHeader: (headers: Headers, apiKey: string) => {
headers.set("authorization", `Bearer ${apiKey}`)
},
parseApiKey: (headers: Headers) => headers.get("authorization")?.split(" ")[1],
onStreamPart: (chunk: string) => {
const [event, data] = chunk.split("\n")
if (event !== "event: response.completed") return
if (!data.startsWith("data: ")) return
let json
try {
json = JSON.parse(data.slice(6)) as { response?: { usage?: Usage } }
} catch (e) {
return
}
if (!json.response?.usage) return
usage = json.response.usage
},
getStreamUsage: () => usage,
normalizeUsage: (usage: Usage) => {
const inputTokens = usage.input_tokens ?? 0
const outputTokens = usage.output_tokens ?? 0
const reasoningTokens = usage.output_tokens_details?.reasoning_tokens ?? undefined
const cacheReadTokens = usage.input_tokens_details?.cached_tokens ?? undefined
return {
inputTokens: inputTokens - (cacheReadTokens ?? 0),
outputTokens: outputTokens - (reasoningTokens ?? 0),
reasoningTokens,
cacheReadTokens,
}
},
})
}
+9
View File
@@ -0,0 +1,9 @@
html {
line-height: 1;
background-color: var(--color-bg);
color: var(--color-text);
}
body {
font-family: var(--font-sans);
}
+102
View File
@@ -0,0 +1,102 @@
[data-component="button"] {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--space-2);
padding: var(--space-3) var(--space-4);
border: 1px solid transparent;
border-radius: var(--space-2);
font-family: var(--font-sans);
font-size: var(--font-size-md);
font-weight: 500;
line-height: 1.25;
cursor: pointer;
transition: all 0.2s ease-in-out;
text-decoration: none;
user-select: none;
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
&:focus {
outline: none;
box-shadow: 0 0 0 2px var(--color-primary);
}
&[data-color="primary"] {
background-color: var(--color-primary);
color: var(--color-primary-text);
border-color: var(--color-primary);
&:hover:not(:disabled) {
background-color: var(--color-primary-hover);
border-color: var(--color-primary-hover);
}
&:active:not(:disabled) {
background-color: var(--color-primary-active);
border-color: var(--color-primary-active);
}
}
&[data-color="danger"] {
background-color: var(--color-danger);
color: var(--color-danger-text);
border-color: var(--color-danger);
&:hover:not(:disabled) {
background-color: var(--color-danger-hover);
border-color: var(--color-danger-hover);
}
&:active:not(:disabled) {
background-color: var(--color-danger-active);
border-color: var(--color-danger-active);
}
&:focus {
box-shadow: 0 0 0 2px var(--color-danger);
}
}
&[data-color="warning"] {
background-color: var(--color-warning);
color: var(--color-warning-text);
border-color: var(--color-warning);
&:hover:not(:disabled) {
background-color: var(--color-warning-hover);
border-color: var(--color-warning-hover);
}
&:active:not(:disabled) {
background-color: var(--color-warning-active);
border-color: var(--color-warning-active);
}
&:focus {
box-shadow: 0 0 0 2px var(--color-warning);
}
}
&[data-size="small"] {
padding: var(--space-2) var(--space-3);
font-size: var(--font-size-sm);
gap: var(--space-1-5);
}
&[data-size="large"] {
padding: var(--space-4) var(--space-6);
font-size: var(--font-size-lg);
gap: var(--space-3);
}
[data-slot="icon"] {
display: flex;
align-items: center;
width: 1em;
height: 1em;
}
}
+8
View File
@@ -0,0 +1,8 @@
@import "./token/color.css";
@import "./token/font.css";
@import "./token/space.css";
@import "./component/button.css";
@import "./reset.css";
@import "./base.css";
+76
View File
@@ -0,0 +1,76 @@
/* 1. Use a more-intuitive box-sizing model */
*,
*::before,
*::after {
box-sizing: border-box;
}
/* 2. Remove default margin */
* {
margin: 0;
}
/* 3. Enable keyword animations */
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords;
}
}
body {
/* 4. Add accessible line-height */
line-height: 1.5;
/* 5. Improve text rendering */
-webkit-font-smoothing: antialiased;
}
/* 6. Improve media defaults */
img,
picture,
video,
canvas,
svg {
display: block;
max-width: 100%;
}
/* 7. Inherit fonts for form controls */
input,
button,
textarea,
select {
font: inherit;
}
/* 8. Avoid text overflows */
p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word;
}
/* 9. Improve line wrapping */
p {
text-wrap: pretty;
}
h1,
h2,
h3,
h4,
h5,
h6 {
text-wrap: balance;
}
/*
10. Create a root stacking context
*/
#root,
#__next {
isolation: isolate;
}
+91
View File
@@ -0,0 +1,91 @@
:root {
--color-white: #ffffff;
--color-black: #000000;
/* Default light theme colors */
--color-bg: #ffffff;
--color-bg-surface: #f5f5f7;
--color-bg-elevated: #ffffff;
--color-text: #1d1d1f;
--color-text-secondary: #424245;
--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-surface-border: var(--color-border);
}
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #0c0c0e;
--color-bg-surface: #161618;
--color-bg-elevated: #1c1c1f;
--color-text: #ffffff;
--color-text-secondary: #c7c7cc;
--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-surface-border: var(--color-border);
}
}
+20
View File
@@ -0,0 +1,20 @@
body {
--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", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--font-sans: var(--font-mono);
}
+46
View File
@@ -0,0 +1,46 @@
body {
--space-0: 0;
--space-px: 1px;
--space-0-5: 0.125rem;
--space-0-75: 0.1875rem;
--space-1: 0.25rem;
--space-1-5: 0.375rem;
--space-2: 0.5rem;
--space-2-5: 0.625rem;
--space-3: 0.75rem;
--space-3-5: 0.875rem;
--space-4: 1rem;
--space-4-5: 1.125rem;
--space-5: 1.25rem;
--space-6: 1.5rem;
--space-7: 1.75rem;
--space-8: 2rem;
--space-9: 2.25rem;
--space-10: 2.5rem;
--space-11: 2.75rem;
--space-12: 3rem;
--space-14: 3.5rem;
--space-16: 4rem;
--space-17: 4.25rem;
--space-18: 4.5rem;
--space-19: 4.75rem;
--space-20: 5rem;
--space-24: 6rem;
--space-28: 7rem;
--space-32: 8rem;
--space-36: 9rem;
--space-40: 10rem;
--space-44: 11rem;
--space-48: 12rem;
--space-52: 13rem;
--space-56: 14rem;
--space-60: 15rem;
--space-64: 16rem;
--space-72: 18rem;
--space-80: 20rem;
--space-96: 24rem;
--border-radius-sm: 0.1875rem;
--border-radius-md: 0.3125rem;
--border-radius-lg: 0.5rem;
}
+531
View File
@@ -0,0 +1,531 @@
import type { APIEvent } from "@solidjs/start/server"
import path from "node:path"
import { and, Database, eq, isNull, sql } from "@opencode/cloud-core/drizzle/index.js"
import { KeyTable } from "@opencode/cloud-core/schema/key.sql.js"
import { BillingTable, UsageTable } from "@opencode/cloud-core/schema/billing.sql.js"
import { centsToMicroCents } from "@opencode/cloud-core/util/price.js"
import { Identifier } from "@opencode/cloud-core/identifier.js"
import { Resource } from "@opencode/cloud-resource"
type ModelCost = {
input: number
output: number
cacheRead?: number
cacheWrite5m?: number
cacheWrite1h?: number
}
type Model = {
id: string
auth: boolean
cost: ModelCost | ((usage: any) => ModelCost)
headerMappings: Record<string, string>
providers: Record<
string,
{
api: string
apiKey: string
model: string
weight?: number
}
>
}
export async function handler(
input: APIEvent,
opts: {
modifyBody?: (body: any) => any
setAuthHeader: (headers: Headers, apiKey: string) => void
parseApiKey: (headers: Headers) => string | undefined
onStreamPart: (chunk: string) => void
getStreamUsage: () => any
normalizeUsage: (body: any) => {
inputTokens: number
outputTokens: number
reasoningTokens?: number
cacheReadTokens?: number
cacheWrite5mTokens?: number
cacheWrite1hTokens?: number
}
},
) {
class AuthError extends Error {}
class CreditsError extends Error {}
class ModelError extends Error {}
const MODELS: Record<string, Model> = {
"claude-opus-4-1": {
id: "claude-opus-4-1" as const,
auth: true,
cost: {
input: 0.000015,
output: 0.000075,
cacheRead: 0.0000015,
cacheWrite5m: 0.00001875,
cacheWrite1h: 0.00003,
},
headerMappings: {},
providers: {
anthropic: {
api: "https://api.anthropic.com",
apiKey: Resource.ANTHROPIC_API_KEY.value,
model: "claude-opus-4-1-20250805",
},
},
},
"claude-sonnet-4": {
id: "claude-sonnet-4" as const,
auth: true,
cost: (usage: any) => {
const totalInputTokens =
usage.inputTokens + usage.cacheReadTokens + usage.cacheWrite5mTokens + usage.cacheWrite1hTokens
return totalInputTokens <= 200_000
? {
input: 0.000003,
output: 0.000015,
cacheRead: 0.0000003,
cacheWrite5m: 0.00000375,
cacheWrite1h: 0.000006,
}
: {
input: 0.000006,
output: 0.0000225,
cacheRead: 0.0000006,
cacheWrite5m: 0.0000075,
cacheWrite1h: 0.000012,
}
},
headerMappings: {},
providers: {
anthropic: {
api: "https://api.anthropic.com",
apiKey: Resource.ANTHROPIC_API_KEY.value,
model: "claude-sonnet-4-20250514",
},
},
},
"claude-3-5-haiku": {
id: "claude-3-5-haiku" as const,
auth: true,
cost: {
input: 0.0000008,
output: 0.000004,
cacheRead: 0.00000008,
cacheWrite5m: 0.000001,
cacheWrite1h: 0.0000016,
},
headerMappings: {},
providers: {
anthropic: {
api: "https://api.anthropic.com",
apiKey: Resource.ANTHROPIC_API_KEY.value,
model: "claude-3-5-haiku-20241022",
},
},
},
"gpt-5": {
id: "gpt-5" as const,
auth: true,
cost: {
input: 0.00000125,
output: 0.00001,
cacheRead: 0.000000125,
},
headerMappings: {},
providers: {
openai: {
api: "https://api.openai.com",
apiKey: Resource.OPENAI_API_KEY.value,
model: "gpt-5",
},
},
},
"qwen3-coder": {
id: "qwen3-coder" as const,
auth: true,
cost: {
input: 0.00000045,
output: 0.0000018,
},
headerMappings: {},
providers: {
baseten: {
api: "https://inference.baseten.co",
apiKey: Resource.BASETEN_API_KEY.value,
model: "Qwen/Qwen3-Coder-480B-A35B-Instruct",
weight: 4,
},
fireworks: {
api: "https://api.fireworks.ai/inference",
apiKey: Resource.FIREWORKS_API_KEY.value,
model: "accounts/fireworks/models/qwen3-coder-480b-a35b-instruct",
weight: 1,
},
},
},
"kimi-k2": {
id: "kimi-k2" as const,
auth: true,
cost: {
input: 0.0000006,
output: 0.0000025,
},
headerMappings: {},
providers: {
baseten: {
api: "https://inference.baseten.co",
apiKey: Resource.BASETEN_API_KEY.value,
model: "moonshotai/Kimi-K2-Instruct-0905",
weight: 4,
},
fireworks: {
api: "https://api.fireworks.ai/inference",
apiKey: Resource.FIREWORKS_API_KEY.value,
model: "accounts/fireworks/models/kimi-k2-instruct-0905",
weight: 1,
},
},
},
"grok-code": {
id: "grok-code" as const,
auth: false,
cost: {
input: 0,
output: 0,
cacheRead: 0,
},
headerMappings: {
"x-grok-conv-id": "x-opencode-session",
"x-grok-req-id": "x-opencode-request",
},
providers: {
xai: {
api: "https://api.x.ai",
apiKey: Resource.XAI_API_KEY.value,
model: "grok-code",
},
},
},
// deprecated
"qwen/qwen3-coder": {
id: "qwen/qwen3-coder" as const,
auth: true,
cost: {
input: 0.00000038,
output: 0.00000153,
},
headerMappings: {},
providers: {
baseten: {
api: "https://inference.baseten.co",
apiKey: Resource.BASETEN_API_KEY.value,
model: "Qwen/Qwen3-Coder-480B-A35B-Instruct",
weight: 5,
},
fireworks: {
api: "https://api.fireworks.ai/inference",
apiKey: Resource.FIREWORKS_API_KEY.value,
model: "accounts/fireworks/models/qwen3-coder-480b-a35b-instruct",
weight: 1,
},
},
},
}
const FREE_WORKSPACES = [
"wrk_01K46JDFR0E75SG2Q8K172KF3Y", // frank
]
const logger = {
metric: (values: Record<string, any>) => {
console.log(`_metric:${JSON.stringify(values)}`)
},
log: console.log,
debug: (message: string) => {
if (Resource.App.stage === "production") return
console.debug(message)
},
}
try {
const url = new URL(input.request.url)
const body = await input.request.json()
logger.debug(JSON.stringify(body))
logger.metric({
is_tream: !!body.stream,
session: input.request.headers.get("x-opencode-session"),
request: input.request.headers.get("x-opencode-request"),
})
const MODEL = validateModel()
const apiKey = await authenticate()
const isFree = FREE_WORKSPACES.includes(apiKey?.workspaceID ?? "")
await checkCredits()
const providerName = selectProvider()
const providerData = MODEL.providers[providerName]
logger.metric({ provider: providerName })
// Request to model provider
const startTimestamp = Date.now()
const res = await fetch(path.posix.join(providerData.api, url.pathname.replace(/^\/zen/, "") + url.search), {
method: "POST",
headers: (() => {
const headers = input.request.headers
headers.delete("host")
headers.delete("content-length")
opts.setAuthHeader(headers, providerData.apiKey)
Object.entries(MODEL.headerMappings ?? {}).forEach(([k, v]) => {
headers.set(k, headers.get(v)!)
})
return headers
})(),
body: JSON.stringify({
...(opts.modifyBody?.(body) ?? body),
model: providerData.model,
}),
})
// Scrub response headers
const resHeaders = new Headers()
const keepHeaders = ["content-type", "cache-control"]
for (const [k, v] of res.headers.entries()) {
if (keepHeaders.includes(k.toLowerCase())) {
resHeaders.set(k, v)
}
}
// Handle non-streaming response
if (!body.stream) {
const json = await res.json()
const body = JSON.stringify(json)
logger.metric({ response_length: body.length })
logger.debug(body)
await trackUsage(json.usage)
return new Response(body, {
status: res.status,
statusText: res.statusText,
headers: resHeaders,
})
}
// Handle streaming response
const stream = new ReadableStream({
start(c) {
const reader = res.body?.getReader()
const decoder = new TextDecoder()
let buffer = ""
let responseLength = 0
function pump(): Promise<void> {
return (
reader?.read().then(async ({ done, value }) => {
if (done) {
logger.metric({ response_length: responseLength })
const usage = opts.getStreamUsage()
if (usage) await trackUsage(usage)
c.close()
return
}
if (responseLength === 0) {
logger.metric({ time_to_first_byte: Date.now() - startTimestamp })
}
responseLength += value.length
buffer += decoder.decode(value, { stream: true })
const parts = buffer.split("\n\n")
buffer = parts.pop() ?? ""
for (const part of parts) {
logger.debug(part)
opts.onStreamPart(part.trim())
}
c.enqueue(value)
return pump()
}) || Promise.resolve()
)
}
return pump()
},
})
return new Response(stream, {
status: res.status,
statusText: res.statusText,
headers: resHeaders,
})
function validateModel() {
if (!(body.model in MODELS)) {
throw new ModelError(`Model ${body.model} not supported`)
}
const model = MODELS[body.model as keyof typeof MODELS]
logger.metric({ model: model.id })
return model
}
async function authenticate() {
try {
const apiKey = opts.parseApiKey(input.request.headers)
if (!apiKey) throw new AuthError("Missing API key.")
const key = await Database.use((tx) =>
tx
.select({
id: KeyTable.id,
workspaceID: KeyTable.workspaceID,
})
.from(KeyTable)
.where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
.then((rows) => rows[0]),
)
if (!key) throw new AuthError("Invalid API key.")
logger.metric({
api_key: key.id,
workspace: key.workspaceID,
})
return key
} catch (e) {
// ignore error if model does not require authentication
if (!MODEL.auth) return
throw e
}
}
async function checkCredits() {
if (!apiKey || !MODEL.auth || isFree) return
const billing = await Database.use((tx) =>
tx
.select({
balance: BillingTable.balance,
})
.from(BillingTable)
.where(eq(BillingTable.workspaceID, apiKey.workspaceID))
.then((rows) => rows[0]),
)
if (billing.balance <= 0) throw new CreditsError("Insufficient balance")
}
function selectProvider() {
const picks = Object.entries(MODEL.providers).flatMap(([name, provider]) =>
Array<string>(provider.weight ?? 1).fill(name),
)
return picks[Math.floor(Math.random() * picks.length)]
}
async function trackUsage(usage: any) {
const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWrite5mTokens, cacheWrite1hTokens } =
opts.normalizeUsage(usage)
const modelCost = typeof MODEL.cost === "function" ? MODEL.cost(usage) : MODEL.cost
const inputCost = modelCost.input * inputTokens * 100
const outputCost = modelCost.output * outputTokens * 100
const reasoningCost = (() => {
if (!reasoningTokens) return undefined
return modelCost.output * reasoningTokens * 100
})()
const cacheReadCost = (() => {
if (!cacheReadTokens) return undefined
if (!modelCost.cacheRead) return undefined
return modelCost.cacheRead * cacheReadTokens * 100
})()
const cacheWrite5mCost = (() => {
if (!cacheWrite5mTokens) return undefined
if (!modelCost.cacheWrite5m) return undefined
return modelCost.cacheWrite5m * cacheWrite5mTokens * 100
})()
const cacheWrite1hCost = (() => {
if (!cacheWrite1hTokens) return undefined
if (!modelCost.cacheWrite1h) return undefined
return modelCost.cacheWrite1h * cacheWrite1hTokens * 100
})()
const totalCostInCent =
inputCost +
outputCost +
(reasoningCost ?? 0) +
(cacheReadCost ?? 0) +
(cacheWrite5mCost ?? 0) +
(cacheWrite1hCost ?? 0)
logger.metric({
"tokens.input": inputTokens,
"tokens.output": outputTokens,
"tokens.reasoning": reasoningTokens,
"tokens.cache_read": cacheReadTokens,
"tokens.cache_write_5m": cacheWrite5mTokens,
"tokens.cache_write_1h": cacheWrite1hTokens,
"cost.input": Math.round(inputCost),
"cost.output": Math.round(outputCost),
"cost.reasoning": reasoningCost ? Math.round(reasoningCost) : undefined,
"cost.cache_read": cacheReadCost ? Math.round(cacheReadCost) : undefined,
"cost.cache_write_5m": cacheWrite5mCost ? Math.round(cacheWrite5mCost) : undefined,
"cost.cache_write_1h": cacheWrite1hCost ? Math.round(cacheWrite1hCost) : undefined,
"cost.total": Math.round(totalCostInCent),
})
if (!apiKey) return
const cost = isFree ? 0 : centsToMicroCents(totalCostInCent)
await Database.transaction(async (tx) => {
await tx.insert(UsageTable).values({
workspaceID: apiKey.workspaceID,
id: Identifier.create("usage"),
model: MODEL.id,
provider: providerName,
inputTokens,
outputTokens,
reasoningTokens,
cacheReadTokens,
cacheWrite5mTokens,
cacheWrite1hTokens,
cost,
})
await tx
.update(BillingTable)
.set({
balance: sql`${BillingTable.balance} - ${cost}`,
})
.where(eq(BillingTable.workspaceID, apiKey.workspaceID))
})
await Database.use((tx) =>
tx
.update(KeyTable)
.set({ timeUsed: sql`now()` })
.where(eq(KeyTable.id, apiKey.id)),
)
}
} catch (error: any) {
logger.metric({
"error.type": error.constructor.name,
"error.message": error.message,
})
// Note: both top level "type" and "error.type" fields are used by the @ai-sdk/anthropic client to render the error message.
if (error instanceof AuthError || error instanceof CreditsError || error instanceof ModelError)
return new Response(
JSON.stringify({
type: "error",
error: { type: error.constructor.name, message: error.message },
}),
{ status: 401 },
)
return new Response(
JSON.stringify({
type: "error",
error: {
type: "error",
message: error.message,
},
}),
{ status: 500 },
)
}
}
+1 -1
View File
@@ -6,4 +6,4 @@
/// <reference path="../../sst-env.d.ts" />
import "sst"
export {}
export {}
+21
View File
@@ -0,0 +1,21 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"allowJs": true,
"strict": true,
"noEmit": true,
"types": ["vinxi/types/client"],
"isolatedModules": true,
"paths": {
"~/*": ["./src/*"]
}
}
}
+20
View File
@@ -0,0 +1,20 @@
import { Resource } from "sst"
import { defineConfig } from "drizzle-kit"
export default defineConfig({
out: "./migrations/",
strict: true,
schema: ["./src/**/*.sql.ts"],
verbose: true,
dialect: "mysql",
dbCredentials: {
database: Resource.Database.database,
host: Resource.Database.host,
user: Resource.Database.username,
password: Resource.Database.password,
port: Resource.Database.port,
ssl: {
rejectUnauthorized: false,
},
},
})
@@ -0,0 +1,89 @@
CREATE TABLE `account` (
`id` varchar(30) NOT NULL,
`time_created` timestamp(3) NOT NULL DEFAULT (now()),
`time_updated` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`time_deleted` timestamp(3),
`email` varchar(255) NOT NULL,
CONSTRAINT `email` UNIQUE(`email`)
);
--> statement-breakpoint
CREATE TABLE `billing` (
`id` varchar(30) NOT NULL,
`workspace_id` varchar(30) NOT NULL,
`time_created` timestamp(3) NOT NULL DEFAULT (now()),
`time_updated` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`time_deleted` timestamp(3),
`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(3) NOT NULL DEFAULT (now()),
`time_updated` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`time_deleted` timestamp(3),
`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(3) NOT NULL DEFAULT (now()),
`time_updated` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`time_deleted` timestamp(3),
`model` varchar(255) NOT NULL,
`input_tokens` int NOT NULL,
`output_tokens` int NOT NULL,
`reasoning_tokens` int,
`cache_read_tokens` int,
`cache_write_tokens` int,
`cost` bigint NOT NULL,
CONSTRAINT `usage_workspace_id_id_pk` PRIMARY KEY(`workspace_id`,`id`)
);
--> statement-breakpoint
CREATE TABLE `key` (
`id` varchar(30) NOT NULL,
`workspace_id` varchar(30) NOT NULL,
`time_created` timestamp(3) NOT NULL DEFAULT (now()),
`time_updated` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`time_deleted` timestamp(3),
`user_id` text NOT NULL,
`name` varchar(255) NOT NULL,
`key` varchar(255) NOT NULL,
`time_used` timestamp(3),
CONSTRAINT `key_workspace_id_id_pk` PRIMARY KEY(`workspace_id`,`id`),
CONSTRAINT `global_key` UNIQUE(`key`)
);
--> statement-breakpoint
CREATE TABLE `user` (
`id` varchar(30) NOT NULL,
`workspace_id` varchar(30) NOT NULL,
`time_created` timestamp(3) NOT NULL DEFAULT (now()),
`time_updated` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`time_deleted` timestamp(3),
`email` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL,
`time_seen` timestamp(3),
`color` int,
CONSTRAINT `user_workspace_id_id_pk` PRIMARY KEY(`workspace_id`,`id`),
CONSTRAINT `user_email` UNIQUE(`workspace_id`,`email`)
);
--> statement-breakpoint
CREATE TABLE `workspace` (
`id` varchar(30) NOT NULL,
`slug` varchar(255),
`name` varchar(255),
`time_created` timestamp(3) NOT NULL DEFAULT (now()),
`time_updated` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`time_deleted` timestamp(3),
CONSTRAINT `workspace_id` PRIMARY KEY(`id`),
CONSTRAINT `slug` UNIQUE(`slug`)
);
@@ -0,0 +1,2 @@
ALTER TABLE `key` ADD `actor` json;--> statement-breakpoint
ALTER TABLE `key` DROP COLUMN `user_id`;
@@ -0,0 +1 @@
ALTER TABLE `key` ADD `old_name` varchar(255);
@@ -0,0 +1 @@
ALTER TABLE `key` ADD CONSTRAINT `name` UNIQUE(`workspace_id`,`name`);
@@ -0,0 +1 @@
ALTER TABLE `usage` ADD `provider` varchar(255);
@@ -0,0 +1 @@
ALTER TABLE `usage` MODIFY COLUMN `provider` varchar(255) NOT NULL;
@@ -0,0 +1,2 @@
ALTER TABLE `usage` ADD `cache_write_5m_tokens` int;--> statement-breakpoint
ALTER TABLE `usage` ADD `cache_write_1h_tokens` int;
@@ -0,0 +1 @@
ALTER TABLE `usage` DROP COLUMN `cache_write_tokens`;
@@ -0,0 +1,569 @@
{
"version": "5",
"dialect": "mysql",
"id": "aee779c5-db1d-4655-95ec-6451c18455be",
"prevId": "00000000-0000-0000-0000-000000000000",
"tables": {
"account": {
"name": "account",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"email": {
"name": "email",
"columns": ["email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraint": {}
},
"billing": {
"name": "billing",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"payment": {
"name": "payment",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"usage": {
"name": "usage",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"input_tokens": {
"name": "input_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"output_tokens": {
"name": "output_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_tokens": {
"name": "cache_write_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"key": {
"name": "key",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_used": {
"name": "time_used",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"global_key": {
"name": "global_key",
"columns": ["key"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"user": {
"name": "user",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_seen": {
"name": "time_seen",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"workspace": {
"name": "workspace",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": ["slug"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": ["id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}
@@ -0,0 +1,569 @@
{
"version": "5",
"dialect": "mysql",
"id": "79b7ee25-1c1c-41ff-9bbf-754af257102b",
"prevId": "aee779c5-db1d-4655-95ec-6451c18455be",
"tables": {
"account": {
"name": "account",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"email": {
"name": "email",
"columns": ["email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraint": {}
},
"billing": {
"name": "billing",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"payment": {
"name": "payment",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"usage": {
"name": "usage",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"input_tokens": {
"name": "input_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"output_tokens": {
"name": "output_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_tokens": {
"name": "cache_write_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"key": {
"name": "key",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"actor": {
"name": "actor",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"key": {
"name": "key",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_used": {
"name": "time_used",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"global_key": {
"name": "global_key",
"columns": ["key"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"user": {
"name": "user",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_seen": {
"name": "time_seen",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"workspace": {
"name": "workspace",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": ["slug"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": ["id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}
@@ -0,0 +1,576 @@
{
"version": "5",
"dialect": "mysql",
"id": "9f51ef52-31ac-4ace-8b6d-39b35efe9c81",
"prevId": "79b7ee25-1c1c-41ff-9bbf-754af257102b",
"tables": {
"account": {
"name": "account",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"email": {
"name": "email",
"columns": ["email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraint": {}
},
"billing": {
"name": "billing",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"payment": {
"name": "payment",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"usage": {
"name": "usage",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"input_tokens": {
"name": "input_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"output_tokens": {
"name": "output_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_tokens": {
"name": "cache_write_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"key": {
"name": "key",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"actor": {
"name": "actor",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"old_name": {
"name": "old_name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_used": {
"name": "time_used",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"global_key": {
"name": "global_key",
"columns": ["key"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"user": {
"name": "user",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_seen": {
"name": "time_seen",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"workspace": {
"name": "workspace",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": ["slug"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": ["id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}
@@ -0,0 +1,581 @@
{
"version": "5",
"dialect": "mysql",
"id": "26cebd59-f553-441c-a2b2-2f9578a0ad2b",
"prevId": "9f51ef52-31ac-4ace-8b6d-39b35efe9c81",
"tables": {
"account": {
"name": "account",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"email": {
"name": "email",
"columns": ["email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraint": {}
},
"billing": {
"name": "billing",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"payment": {
"name": "payment",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"usage": {
"name": "usage",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"input_tokens": {
"name": "input_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"output_tokens": {
"name": "output_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_tokens": {
"name": "cache_write_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"key": {
"name": "key",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"actor": {
"name": "actor",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"old_name": {
"name": "old_name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_used": {
"name": "time_used",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"global_key": {
"name": "global_key",
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"user": {
"name": "user",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_seen": {
"name": "time_seen",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"workspace": {
"name": "workspace",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": ["slug"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": ["id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}
@@ -0,0 +1,588 @@
{
"version": "5",
"dialect": "mysql",
"id": "06dc6226-bfbb-4ccc-b4bc-f26070c3bed5",
"prevId": "26cebd59-f553-441c-a2b2-2f9578a0ad2b",
"tables": {
"account": {
"name": "account",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"email": {
"name": "email",
"columns": ["email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraint": {}
},
"billing": {
"name": "billing",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"payment": {
"name": "payment",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"usage": {
"name": "usage",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"provider": {
"name": "provider",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"input_tokens": {
"name": "input_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"output_tokens": {
"name": "output_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_tokens": {
"name": "cache_write_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"key": {
"name": "key",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"actor": {
"name": "actor",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"old_name": {
"name": "old_name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_used": {
"name": "time_used",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"global_key": {
"name": "global_key",
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"user": {
"name": "user",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_seen": {
"name": "time_seen",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"workspace": {
"name": "workspace",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": ["slug"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": ["id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}
@@ -0,0 +1,588 @@
{
"version": "5",
"dialect": "mysql",
"id": "d13af80e-3c70-4866-8f14-48e7ff6ff0ff",
"prevId": "06dc6226-bfbb-4ccc-b4bc-f26070c3bed5",
"tables": {
"account": {
"name": "account",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"email": {
"name": "email",
"columns": ["email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraint": {}
},
"billing": {
"name": "billing",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"payment": {
"name": "payment",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"usage": {
"name": "usage",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"provider": {
"name": "provider",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"input_tokens": {
"name": "input_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"output_tokens": {
"name": "output_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_tokens": {
"name": "cache_write_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"key": {
"name": "key",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"actor": {
"name": "actor",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"old_name": {
"name": "old_name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_used": {
"name": "time_used",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"global_key": {
"name": "global_key",
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"user": {
"name": "user",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_seen": {
"name": "time_seen",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"workspace": {
"name": "workspace",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": ["slug"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": ["id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}
@@ -0,0 +1,602 @@
{
"version": "5",
"dialect": "mysql",
"id": "b0ad4b11-b607-46c7-8e2d-3b9823cdc5f7",
"prevId": "d13af80e-3c70-4866-8f14-48e7ff6ff0ff",
"tables": {
"account": {
"name": "account",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"email": {
"name": "email",
"columns": ["email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraint": {}
},
"billing": {
"name": "billing",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"payment": {
"name": "payment",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"usage": {
"name": "usage",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"provider": {
"name": "provider",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"input_tokens": {
"name": "input_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"output_tokens": {
"name": "output_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_tokens": {
"name": "cache_write_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_5m_tokens": {
"name": "cache_write_5m_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_1h_tokens": {
"name": "cache_write_1h_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"key": {
"name": "key",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"actor": {
"name": "actor",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"old_name": {
"name": "old_name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_used": {
"name": "time_used",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"global_key": {
"name": "global_key",
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"user": {
"name": "user",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_seen": {
"name": "time_seen",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"workspace": {
"name": "workspace",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": ["slug"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": ["id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}
@@ -0,0 +1,595 @@
{
"version": "5",
"dialect": "mysql",
"id": "91067cc9-d492-47b3-932a-42dcc0920b3c",
"prevId": "b0ad4b11-b607-46c7-8e2d-3b9823cdc5f7",
"tables": {
"account": {
"name": "account",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"email": {
"name": "email",
"columns": ["email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraint": {}
},
"billing": {
"name": "billing",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_id": {
"name": "payment_method_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_method_last4": {
"name": "payment_method_last4",
"type": "varchar(4)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"balance": {
"name": "balance",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reload": {
"name": "reload",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"payment": {
"name": "payment",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"customer_id": {
"name": "customer_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"payment_id": {
"name": "payment_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"amount": {
"name": "amount",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"usage": {
"name": "usage",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"model": {
"name": "model",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"provider": {
"name": "provider",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"input_tokens": {
"name": "input_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"output_tokens": {
"name": "output_tokens",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"reasoning_tokens": {
"name": "reasoning_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_read_tokens": {
"name": "cache_read_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_5m_tokens": {
"name": "cache_write_5m_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cache_write_1h_tokens": {
"name": "cache_write_1h_tokens",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"cost": {
"name": "cost",
"type": "bigint",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"key": {
"name": "key",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"actor": {
"name": "actor",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"old_name": {
"name": "old_name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"key": {
"name": "key",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_used": {
"name": "time_used",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"global_key": {
"name": "global_key",
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"user": {
"name": "user",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"workspace_id": {
"name": "workspace_id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"time_seen": {
"name": "time_seen",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"color": {
"name": "color",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"user_email": {
"name": "user_email",
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"workspace": {
"name": "workspace",
"columns": {
"id": {
"name": "id",
"type": "varchar(30)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"time_created": {
"name": "time_created",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"time_updated": {
"name": "time_updated",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
},
"time_deleted": {
"name": "time_deleted",
"type": "timestamp(3)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"slug": {
"name": "slug",
"columns": ["slug"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": ["id"]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}
+62
View File
@@ -0,0 +1,62 @@
{
"version": "7",
"dialect": "mysql",
"entries": [
{
"idx": 0,
"version": "5",
"when": 1756796050935,
"tag": "0000_fluffy_raza",
"breakpoints": true
},
{
"idx": 1,
"version": "5",
"when": 1756871639102,
"tag": "0001_serious_whistler",
"breakpoints": true
},
{
"idx": 2,
"version": "5",
"when": 1757597611832,
"tag": "0002_violet_loners",
"breakpoints": true
},
{
"idx": 3,
"version": "5",
"when": 1757600397194,
"tag": "0003_dusty_clint_barton",
"breakpoints": true
},
{
"idx": 4,
"version": "5",
"when": 1757627357232,
"tag": "0004_first_mockingbird",
"breakpoints": true
},
{
"idx": 5,
"version": "5",
"when": 1757632304856,
"tag": "0005_jazzy_skrulls",
"breakpoints": true
},
{
"idx": 6,
"version": "5",
"when": 1757643108507,
"tag": "0006_parallel_gauntlet",
"breakpoints": true
},
{
"idx": 7,
"version": "5",
"when": 1757693869142,
"tag": "0007_familiar_nightshade",
"breakpoints": true
}
]
}
+29
View File
@@ -0,0 +1,29 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode/cloud-core",
"version": "0.7.7",
"private": true,
"type": "module",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@opencode/cloud-resource": "workspace:*",
"@planetscale/database": "1.19.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",
"db-dev": "sst shell --stage dev -- drizzle-kit",
"db-prod": "sst shell --stage production -- drizzle-kit",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"drizzle-kit": "0.30.5",
"mysql2": "3.14.4"
}
}
+67
View File
@@ -0,0 +1,67 @@
import { z } from "zod"
import { and, eq, getTableColumns, isNull } from "drizzle-orm"
import { fn } from "./util/fn"
import { Database } from "./drizzle"
import { Identifier } from "./identifier"
import { AccountTable } from "./schema/account.sql"
import { Actor } from "./actor"
import { WorkspaceTable } from "./schema/workspace.sql"
import { UserTable } from "./schema/user.sql"
export namespace Account {
export const create = fn(
z.object({
email: z.string().email(),
id: z.string().optional(),
}),
async (input) =>
Database.transaction(async (tx) => {
const id = input.id ?? Identifier.create("account")
await tx.insert(AccountTable).values({
id,
email: input.email,
})
return id
}),
)
export const fromID = fn(z.string(), async (id) =>
Database.transaction(async (tx) => {
return tx
.select()
.from(AccountTable)
.where(eq(AccountTable.id, id))
.execute()
.then((rows) => rows[0])
}),
)
export const fromEmail = fn(z.string().email(), async (email) =>
Database.transaction(async (tx) => {
return tx
.select()
.from(AccountTable)
.where(eq(AccountTable.email, email))
.execute()
.then((rows) => rows[0])
}),
)
export const workspaces = async () => {
const actor = Actor.assert("account")
return Database.transaction(async (tx) =>
tx
.select(getTableColumns(WorkspaceTable))
.from(WorkspaceTable)
.innerJoin(UserTable, eq(UserTable.workspaceID, WorkspaceTable.id))
.where(
and(
eq(UserTable.email, actor.properties.email),
isNull(UserTable.timeDeleted),
isNull(WorkspaceTable.timeDeleted),
),
)
.execute(),
)
}
}
+74
View File
@@ -0,0 +1,74 @@
import { Context } from "./context"
import { Log } from "./util/log"
export namespace Actor {
interface Account {
type: "account"
properties: {
accountID: string
email: string
}
}
interface Public {
type: "public"
properties: {}
}
interface User {
type: "user"
properties: {
userID: string
workspaceID: string
}
}
interface System {
type: "system"
properties: {
workspaceID: string
}
}
export type Info = Account | Public | User | System
const ctx = Context.create<Info>()
export const use = ctx.use
const log = Log.create().tag("namespace", "actor")
export function provide<R, T extends Info["type"]>(
type: T,
properties: Extract<Info, { type: T }>["properties"],
cb: () => R,
) {
return ctx.provide(
{
type,
properties,
} as any,
() => {
return Log.provide({ ...properties }, () => {
log.info("provided")
return cb()
})
},
)
}
export function assert<T extends Info["type"]>(type: T) {
const actor = use()
if (actor.type !== type) {
throw new Error(`Expected actor type ${type}, got ${actor.type}`)
}
return actor as Extract<Info, { type: T }>
}
export function workspace() {
const actor = use()
if ("workspaceID" in actor.properties) {
return actor.properties.workspaceID
}
throw new Error(`actor of type "${actor.type}" is not associated with a workspace`)
}
}

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