Compare commits

..

180 Commits

Author SHA1 Message Date
opencode b3490fa33b release: v1.0.44 2025-11-07 21:24:15 +00:00
Dax Raad 0cfdc4d432 tui: show more sessions in list and fix sync timing to prevent race conditions 2025-11-07 16:19:44 -05:00
Aiden Cline 655872415b ignore: update version 2025-11-07 15:18:44 -06:00
Aiden Cline 1d611a950e ci: auto update zed extension 2025-11-07 15:17:26 -06:00
GitHub Action a4eceb9c91 chore: format code 2025-11-07 21:09:47 +00:00
Aiden Cline 48e36580b0 ignore: update zed extension 2025-11-07 15:08:50 -06:00
opencode 447f4e488c release: v1.0.43 2025-11-07 21:04:26 +00:00
Dax Raad 1ec105e42f ci: add optional version parameter to publish workflow
Allows overriding the version when publishing releases instead of only using semantic bumping. This gives maintainers more control over release versioning for special cases or hotfixes.
2025-11-07 15:58:51 -05:00
Sebastian Herrlinger b4f9819c8c upgrade to opentui to fix disappearing content (again) and sticky scroll 2025-11-07 21:38:40 +01:00
Aiden Cline e85481f3ca fix formatters 2025-11-07 14:10:20 -06:00
Aiden Cline fe16b7222b chore: rm debug logs 2025-11-07 14:00:18 -06:00
Adam d5d118580e fix(desktop): stop icon size 2025-11-07 13:58:52 -06:00
Aiden Cline 59ced2ad02 rework acp to compensate for changes in Zed IDE (#4050) 2025-11-07 13:57:12 -06:00
Adam 52ad608fb2 fix(desktop): prompt input issues (wip) 2025-11-07 13:54:53 -06:00
Adam 7d4423dcef fix(desktop): prompt input on non-chat tabs 2025-11-07 13:54:53 -06:00
Dax Raad b36d76be17 Add command bar action to rename sessions 2025-11-07 14:51:44 -05:00
GitHub Action c8c99ada84 chore: format code 2025-11-07 19:47:53 +00:00
Dax Raad 41b5ce67c3 fix: update references after moving message functions to MessageV2 namespace 2025-11-07 14:47:05 -05:00
Adam 394e86c7af chore(desktop): remove dead code 2025-11-07 13:34:41 -06:00
Adam 075b7b5667 chore(desktop): cleanup shiki theme stuff 2025-11-07 13:30:07 -06:00
Adam 3ef6de2aab fix(desktop): code tab padding 2025-11-07 13:14:57 -06:00
Adam b2d32a30c7 fix(desktop): prompt input missing on new session 2025-11-07 12:56:07 -06:00
Adam 89a81dd1dc feat(desktop): custom syntax colors 2025-11-07 12:48:17 -06:00
Dax Raad d4e3ee6f81 fix scroll when no session exists 2025-11-07 13:22:03 -05:00
GitHub Action be44cc4f4a chore: format code 2025-11-07 18:11:40 +00:00
opencode 28e420ba12 release: v1.0.41 2025-11-07 18:11:39 +00:00
Dax Raad 958c991fe1 allow not specifying a limit on messages endpoint 2025-11-07 13:05:19 -05:00
opencode ae456e6bd0 release: v1.0.40 2025-11-07 17:37:31 +00:00
Dax Raad ce4397bc58 disable scrollbar temporarily because of text wrap issues 2025-11-07 12:31:28 -05:00
Jinhyeok Lee e716472023 vscode: Add VS Code Insiders support (#4019) 2025-11-07 10:31:16 -06:00
Adam 97c0385625 ignore: test file 2025-11-07 09:05:09 -06:00
Adam 47dd332694 fix(desktop): layout quirks 2025-11-07 06:26:26 -06:00
GitHub Action 072d5ffe52 ignore: update download stats 2025-11-07 2025-11-07 12:04:25 +00:00
Dax Raad e1e6b9b86f message storage performance improvements 2025-11-07 01:11:47 -05:00
Charles David Mupende 0b7c4ec0e6 feat: implement network IP retrieval for remote access in web command (#3945) 2025-11-06 19:37:23 -06:00
opencode-agent[bot] 27b5482979 Fixed ACP to respect user's default model config. (#4006)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2025-11-06 19:07:27 -06:00
GitHub Action 2636d50237 chore: format code 2025-11-07 01:06:38 +00:00
Nicolai van der Smagt 0fd59de486 fix: resolve Mistral API compatibility issues (#2440)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2025-11-06 20:05:59 -05:00
opencode e0b9113634 release: v1.0.39 2025-11-07 01:04:05 +00:00
Dax Raad bfda88d84b fix issue with input randomly breaking 2025-11-06 19:48:10 -05:00
GitHub Action 00c9ea9f6d chore: format code 2025-11-07 00:14:59 +00:00
Dax Raad 5be6405521 codex tweaks 2025-11-06 19:14:01 -05:00
opencode dc6ccd8184 release: v1.0.37 2025-11-06 23:14:32 +00:00
Dax f68e50e0ff system theme (#4010) 2025-11-06 18:00:09 -05:00
Nicolai van der Smagt e189c90cc0 fix: resolve Mistral API compatibility issues (#2440)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2025-11-06 16:53:02 -06:00
Jay V ceac48b6b9 docs: add Deep Infra provider documentation 2025-11-06 17:08:55 -05:00
Adam 89294f7d8d fix(desktop): diff highlight rendering 2025-11-06 15:58:45 -06:00
Adam dccc25b6ba fix(desktop): review tab padding 2025-11-06 15:34:47 -06:00
Adam 650ed0cf47 feat(desktop): review flow 2025-11-06 15:13:06 -06:00
Shanjai Raj 4bbb015cbb Fix: Auto-scroll to bottom when selecting session from list (#3988)
Co-authored-by: shanjairaj7 <shanjairaj7@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2025-11-06 14:29:39 -06:00
Frank 329d843f0d Add desktop-feedback 2025-11-06 14:29:11 -05:00
GitHub Action 76f1e2ea69 chore: format code 2025-11-06 18:59:34 +00:00
Jay V 8ddf46ad4b docs: align web package favicon with console design for consistency 2025-11-06 13:58:52 -05:00
opencode ac55128ba7 release: v1.0.36 2025-11-06 18:55:54 +00:00
GitHub Action 455cb0d80c chore: format code 2025-11-06 18:21:59 +00:00
Dax Raad aaa60022b7 only display last 100 messages in TUI 2025-11-06 13:21:15 -05:00
Aiden Cline de093ce764 fix: opencode run not parsing model string 2025-11-06 12:09:13 -06:00
Dax Raad a1f2e6bf93 flaky test 2025-11-06 13:05:53 -05:00
GitHub Action 161e61fb7b chore: format code 2025-11-06 18:03:50 +00:00
Dax Raad ed8913324e big format 2025-11-06 13:03:12 -05:00
Aiden Cline 28b66f7b78 update import command to accept share links 2025-11-06 11:55:57 -06:00
Aiden Cline 42c1bc10b9 ci: update auto label 2025-11-06 11:46:42 -06:00
Dax Raad 2bd3f72eb6 fix tests 2025-11-06 11:42:46 -05:00
Aiden Cline aeef860dab chore: rm hanging test 2025-11-06 10:39:32 -06:00
Dax Raad 76dfff8640 fix undo command breaking other commands 2025-11-06 11:25:37 -05:00
Adam 0cfea58263 fix(desktop): sidebar collapsed width 2025-11-06 09:56:46 -06:00
Adam 31d1302212 fix(desktop): demo type error 2025-11-06 09:49:39 -06:00
Adam 929bffb681 feat(desktop): collapsible sidebar 2025-11-06 09:48:51 -06:00
Adam f4a1c1519e fix(desktop): button styles 2025-11-06 09:48:50 -06:00
Adam c473fe33f4 feat(desktop): better tooltips 2025-11-06 09:48:50 -06:00
GitHub Action a37fcce006 ignore: update download stats 2025-11-06 2025-11-06 12:04:56 +00:00
opencode-agent[bot] 0f5e80a68e Added big dot (●) indicator for current session in modal (#3980)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2025-11-06 01:09:59 -06:00
Frank df02a36325 Update sst 2025-11-06 05:42:25 +00:00
opencode acd27edf8a release: v1.0.35 2025-11-06 05:42:24 +00:00
Dax Raad 91a050328b fix homebrew upgrade 2025-11-06 00:37:44 -05:00
opencode bcffeeb26a release: v1.0.34 2025-11-06 02:35:17 +00:00
Dax Raad 3aaa1cf181 tui: reduce scrollbar visual prominence for less distracting interface 2025-11-05 21:30:40 -05:00
Dax Raad fb78d22ff6 enable scrollbar 2025-11-05 21:27:23 -05:00
opencode defe03cde5 release: v1.0.33 2025-11-06 02:18:41 +00:00
Dax Raad 4edf1ee5d0 tui: move debug shortcuts to command palette for better discoverability 2025-11-05 21:13:35 -05:00
Sebastian Herrlinger 5223d96bb0 upgrade to opentui v0.1.36 2025-11-06 01:43:35 +00:00
opencode 086292a647 release: v1.0.32 2025-11-06 01:43:35 +00:00
Dax Raad aba9f666fa temporarily use strip-ansi package till bun bug is fixed 2025-11-05 20:38:37 -05:00
opencode 880c16c452 release: v1.0.31 2025-11-06 01:35:40 +00:00
Dax Raad bbffe8762b ignore tmp type rrror 2025-11-05 20:31:13 -05:00
Dax Raad 4518792feb regen bunlock 2025-11-05 20:30:40 -05:00
Dax Raad aad0d4f84a type errors 2025-11-05 20:14:31 -05:00
Dax Raad 6ab763a137 fix log 2025-11-05 20:01:57 -05:00
Dax Raad 3dac0fc972 fix log 2025-11-05 20:00:09 -05:00
Sebastian Herrlinger cf6956464c upgrade to opentui 0.1.35, mitigating disappearing content and crashes 2025-11-06 01:38:58 +01:00
Dax Raad 3d1d063695 core: ensure export command output can be piped without UI interference 2025-11-05 18:36:06 -05:00
opencode 452149c7aa release: v1.0.30 2025-11-05 23:32:22 +00:00
Dax Raad ba20173827 temporarily remove bun strip ansi due to bug 2025-11-05 18:27:19 -05:00
Dax Raad dfec00e953 add opencode import command to restore sessions from JSON exports 2025-11-05 18:05:01 -05:00
Adam d49fe36eba feat(desktop): incrementally load sessions in side nav 2025-11-05 16:32:08 -06:00
opencode 0bc48ea1e0 release: v1.0.29 2025-11-05 22:14:46 +00:00
Aiden Cline 5d5df3ce6a ask instead of throwing tool error if file is outside cwd 2025-11-05 16:09:47 -06:00
Adam a4c4be047f fix(desktop): max height on message diffs, session stats 2025-11-05 16:00:20 -06:00
Dax Raad 7ae96137f1 fix sidebar modified files 2025-11-05 16:49:17 -05:00
opencode 64bd8ec007 release: v1.0.28 2025-11-05 21:08:58 +00:00
Aiden Cline d7b39d8529 acp: update auth method 2025-11-05 15:01:14 -06:00
Aiden Cline 390da35072 acp: default to big pickle 2025-11-05 14:59:02 -06:00
opencode 8dfd615f4b release: v1.0.27 2025-11-05 20:44:40 +00:00
Dax Raad d99f1f4570 performance improvements 2025-11-05 15:33:23 -05:00
Dax Raad 341e6b8c5a include file count in summary 2025-11-05 14:23:10 -05:00
Dax Raad b1014c0c72 ci: fix aur package 2025-11-05 14:22:25 -05:00
Haris Gušić 1088b49c83 fix(autocomplete): Prioritize exact matches (#3760) 2025-11-05 12:25:05 -06:00
Adam 53b5fbfde9 fix(desktop): local dev url 2025-11-05 12:09:30 -06:00
opencode 93e6522736 release: v1.0.26 2025-11-05 18:08:19 +00:00
Adam 04c3db62cd fix(desktop): type issue 2025-11-05 11:59:10 -06:00
Adam 60dafbf112 fix(desktop): type issue 2025-11-05 11:56:32 -06:00
Adam faeab2f02f feat(desktop): session router, interrupt agent, visual cleanup 2025-11-05 11:55:35 -06:00
OpeOginni c9b327756b fix(tui): restructure Sidebar component to be scrollable (#3946) 2025-11-05 11:33:30 -06:00
Dax Raad c82370e4a4 tui: lower paste summary threshold to trigger on shorter content 2025-11-05 12:32:23 -05:00
monke-yo 5b0468031f feat: add --attach flag to opencode run (#3889) 2025-11-05 11:31:01 -06:00
Filip ee8b763994 chore: remove unused patch tool from registry (to avoid accidental inclusions of it) (#3938) 2025-11-05 11:26:28 -06:00
Aiden Cline 7d29890d25 fix: eu-west-2 aws bedrock issue 2025-11-05 10:14:08 -06:00
Aiden Cline 51f6fdf58c tweak: normalize escape keybind 2025-11-05 10:13:04 -06:00
Matthew Fitzpatrick d8a7940000 docs: include "limit" example (#3925)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2025-11-05 09:47:11 -06:00
Aiden Cline a7594ae81c ci: adjust auto label 2025-11-05 09:36:38 -06:00
GitHub Action a794c33a95 ignore: update download stats 2025-11-05 2025-11-05 12:04:41 +00:00
opencode 83becb03a6 release: v1.0.25 2025-11-05 07:00:07 +00:00
Aiden Cline 37e2c86fe0 ACP: update package, fix slash command bug (#3906) 2025-11-05 00:50:48 -06:00
Aiden Cline 7061298d94 allow @ agents to work even if not first thing in prompt 2025-11-04 23:37:09 -06:00
Christian Stewart 5ec128cbdd feat(tui): add /export and /copy commands (#3883)
Signed-off-by: Christian Stewart <christian@aperture.us>
2025-11-04 23:02:45 -06:00
Err 24b78b7423 feat: add Clojure syntax highlighting support (#3912)
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2025-11-04 22:47:05 -06:00
Dax Raad 5ed30dc7ea tui: fix command validation to prevent invalid commands from being executed 2025-11-04 20:46:01 -05:00
Kyle F Butts f5b25b6d9a Add support for R formatter in formatters (#3918)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2025-11-04 18:18:33 -06:00
opencode c82387f0ee release: v1.0.24 2025-11-05 00:12:19 +00:00
Dax Raad e0a27c8b84 tui: fix session abort when autocomplete is visible 2025-11-04 18:45:39 -05:00
Aiden Cline e104282f96 fix: image reading error, also add error toast for event bus 2025-11-04 17:30:58 -06:00
Frank 4ad73030c2 wip: zen 2025-11-04 17:54:08 -05:00
Jay V 2d174cf785 ignore: update meta description to use proper OpenCode capitalization 2025-11-04 17:27:22 -05:00
Frank 954e559640 wip: zen 2025-11-04 17:24:20 -05:00
Frank 1b2111dd23 wip: zen 2025-11-04 17:24:20 -05:00
Frank e56920ab95 zen: custom reload amount 2025-11-04 17:24:20 -05:00
Dax Raad fe4bdb6742 add command bar option to interrupt session 2025-11-04 17:11:07 -05:00
Aiden Cline 7eda7b9eaa fix: permissions not responding to esc 2025-11-04 16:08:31 -06:00
Jared A. Scheel 9c2c86c52f Add support for uv format in formatters (#3916) 2025-11-04 15:40:29 -06:00
Ola bf4d4ea0ae feat(provider): add GitHub Enterprise support for Copilot (#2522)
Co-authored-by: Jon-Mikkel Korsvik <48263282+jkorsvik@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2025-11-04 15:36:12 -06:00
opencode 7e2c543744 release: v1.0.23 2025-11-04 19:38:18 +00:00
Timo Clasen 2060182b25 feat(TUI): add autocomplete readline style keybinds (#3717)
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
2025-11-04 13:28:03 -06:00
Aiden Cline 3010a2212b fix: stop showing auto complete if user types a space 2025-11-04 13:22:18 -06:00
Dax Raad a122c9c1e1 tui: add ability to interrupt running sessions from command palette 2025-11-04 14:07:22 -05:00
opencode ef39bf549a release: v1.0.22 2025-11-04 18:41:38 +00:00
Dax Raad 643352d20e fix session performance issue from large diffs 2025-11-04 13:35:44 -05:00
opencode 4ca50dda89 release: v1.0.21 2025-11-04 17:47:34 +00:00
Sebastian Herrlinger 3479a5d39f Revert "upgrade opentui to address disappearing content issues #3776, #3697"
This reverts commit a21cf346d7.
2025-11-04 18:38:44 +01:00
Dax Raad f1bc996cf5 local web 2025-11-04 12:33:14 -05:00
Aiden Cline bd69345e7f respect: disable_paste_summary 2025-11-04 11:29:12 -06:00
Aiden Cline 464709c69c fix: /undo command 2025-11-04 10:59:34 -06:00
Christian Stewart 57dc67f27a fix(tui): worker path resolution in dev mode (#3778)
Signed-off-by: Christian Stewart <christian@cjs.zip>
Co-authored-by: Sebastian Herrlinger <hasta84@gmail.com>
2025-11-04 17:38:11 +01:00
Err 20a17386d1 fix: support scoped npm plugins (#3785)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2025-11-04 09:15:01 -06:00
Pranshu Raj f214076457 [FIX]: Refocus prompt after session delete (#3882) 2025-11-04 08:57:59 -06:00
frankdierolf 098cc000fe fix: correct history_next keybinding description (#3891) 2025-11-04 08:52:49 -06:00
arc-source-coder 05615b2929 tui: make /mcp an alias for /status (#3894) 2025-11-04 08:52:28 -06:00
Sebastian Herrlinger a21cf346d7 upgrade opentui to address disappearing content issues #3776, #3697 2025-11-04 14:57:15 +01:00
Adam d7bf177aa9 fix: lander specs 2025-11-04 06:15:12 -06:00
GitHub Action 86944cf792 ignore: update download stats 2025-11-04 2025-11-04 12:05:02 +00:00
Aiden Cline 7a45bf4e77 update brew handling 2025-11-04 00:52:26 -06:00
opencode 436640374e release: v1.0.20 2025-11-04 05:56:24 +00:00
Dax Raad abe25eda0e tui: fix tool permission lookup to use correct session ID 2025-11-04 00:50:12 -05:00
Dax Raad 9ebdccea03 fix: persist -m model when switching agents
Add initial model from command line to fallback chain so it persists
when switching agents with tab, matching behavior of config model.

Resolves #3863
2025-11-03 23:51:52 -05:00
Aiden Cline 03539a049f fix: piping 2025-11-03 22:36:10 -06:00
Dax Raad da1670a0c7 fix: handle parsePatch errors in TUI to prevent crashes
Wrap parsePatch calls in try-catch blocks to gracefully handle malformed
diffs that can occur when undoing after tool_use/tool_result errors or
cancelled prompts. Prevents TUI from crashing with 'Added line count did not
match for hunk' error.

Fixes #3700
2025-11-03 23:36:04 -05:00
Greg Pstrucha 30f3f7f6c8 Fix file tagging in multi line inputs (#3865) 2025-11-03 23:22:38 -05:00
Aiden Cline c5f902d7a3 ignore: delete unused code 2025-11-04 04:01:22 +00:00
Stephen Collings bbd2f1cebd fix: Provide OPENCODE & AGENT env vars (#3843)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2025-11-04 04:01:22 +00:00
Dax Raad 8c46a89732 tui: use keybind helper for history navigation to respect custom keybindings 2025-11-04 04:01:22 +00:00
opencode 7663b23420 release: v1.0.19 2025-11-04 04:01:22 +00:00
Dax Raad 3bd0c0899f tui: fix model selection for models with nested paths
Users can now select models with multiple slashes like 'openrouter/google/gemini-2.5-pro'
in the TUI. Previously the TUI would only parse the first two parts of the model
path, showing 'Invalid model openrouter/google' for nested models.
2025-11-03 19:52:43 -05:00
kaanmertkoc 6d17e71892 feat: implement stats command (#3832) 2025-11-03 18:41:30 -06:00
Mikhail Wahib baa9ef9e10 fix: print the modified keybind for command_list (#3859) 2025-11-03 18:29:23 -06:00
Jay V 3d17962fa2 ignore: lander 2025-11-03 18:17:32 -05:00
Frank 94b897eb5d wip: zen 2025-11-03 17:30:18 -05:00
Adi Yeroslav e949513444 fix: update logo (#3833) 2025-11-03 16:18:38 -06:00
Aiden Cline 0591f2f656 ci: auto label web 2025-11-03 16:17:53 -06:00
Dax Raad d943db71db fix: correct dirs parameter type in file search 2025-11-03 17:10:31 -05:00
Dax Raad 1fedcaf7ae tui: remove duplicate copy message command entry 2025-11-03 17:10:20 -05:00
Dax Raad 9076376ba6 ci: stuff 2025-11-03 22:01:30 +00:00
315 changed files with 11398 additions and 11464 deletions
+24 -2
View File
@@ -11,7 +11,7 @@ jobs:
contents: read
issues: write
steps:
- name: Add opentui label
- name: Auto-label and assign issues
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -20,10 +20,32 @@ jobs:
const title = issue.title;
const description = issue.body || '';
// Check for "opencode web" keyword
const webPattern = /(opencode web)/i;
const isWebRelated = webPattern.test(title) || webPattern.test(description);
// Check for version patterns like v1.0.x or 1.0.x
const versionPattern = /[v]?1\.0\./i;
const isVersionRelated = versionPattern.test(title) || versionPattern.test(description);
if (versionPattern.test(title) || versionPattern.test(description)) {
if (isWebRelated) {
// Add web label
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: ['web']
});
// Assign to adamdotdevin
await github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
assignees: ['adamdotdevin']
});
} else if (isVersionRelated) {
// Only add opentui if NOT web-related
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
+5
View File
@@ -12,6 +12,10 @@ on:
- major
- minor
- patch
version:
description: "Override version (optional)"
required: false
type: string
concurrency: ${{ github.workflow }}-${{ github.ref }}
@@ -62,6 +66,7 @@ jobs:
./script/publish.ts
env:
OPENCODE_BUMP: ${{ inputs.bump }}
OPENCODE_VERSION: ${{ inputs.version }}
OPENCODE_CHANNEL: latest
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
+2
View File
@@ -11,3 +11,5 @@ playground
tmp
dist
.turbo
**/.serena
.serena/
+23 -23
View File
@@ -21,27 +21,27 @@
json
{
"recipient_name": "multi_tool_use.parallel",
"parameters": {
"tool_uses": [
{
"recipient_name": "functions.read",
"parameters": {
"filePath": "path/to/file.tsx"
}
},
{
"recipient_name": "functions.read",
"parameters": {
"filePath": "path/to/file.ts"
}
},
{
"recipient_name": "functions.read",
"parameters": {
"filePath": "path/to/file.md"
}
}
]
}
"recipient_name": "multi_tool_use.parallel",
"parameters": {
"tool_uses": [
{
"recipient_name": "functions.read",
"parameters": {
"filePath": "path/to/file.tsx"
}
},
{
"recipient_name": "functions.read",
"parameters": {
"filePath": "path/to/file.ts"
}
},
{
"recipient_name": "functions.read",
"parameters": {
"filePath": "path/to/file.md"
}
}
]
}
}
+4
View File
@@ -129,3 +129,7 @@
| 2025-11-01 | 636,100 (+9,488) | 581,806 (+17,227) | 1,217,906 (+26,715) |
| 2025-11-02 | 644,067 (+7,967) | 590,004 (+8,198) | 1,234,071 (+16,165) |
| 2025-11-03 | 653,130 (+9,063) | 597,139 (+7,135) | 1,250,269 (+16,198) |
| 2025-11-04 | 663,912 (+10,782) | 608,056 (+10,917) | 1,271,968 (+21,699) |
| 2025-11-05 | 675,074 (+11,162) | 619,690 (+11,634) | 1,294,764 (+22,796) |
| 2025-11-06 | 686,252 (+11,178) | 630,885 (+11,195) | 1,317,137 (+22,373) |
| 2025-11-07 | 696,646 (+10,394) | 642,146 (+11,261) | 1,338,792 (+21,655) |
+153 -130
View File
@@ -11,7 +11,7 @@
"@tsconfig/bun": "catalog:",
"husky": "9.1.7",
"prettier": "3.6.2",
"sst": "3.17.19",
"sst": "3.17.22",
"turbo": "2.5.6",
},
},
@@ -39,7 +39,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.0.18",
"version": "1.0.44",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -66,7 +66,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.0.18",
"version": "1.0.44",
"dependencies": {
"@ai-sdk/anthropic": "2.0.0",
"@ai-sdk/openai": "2.0.2",
@@ -90,7 +90,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.0.18",
"version": "1.0.44",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -111,7 +111,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.0.18",
"version": "1.0.44",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@@ -121,6 +121,7 @@
"@solid-primitives/event-bus": "1.1.2",
"@solid-primitives/resize-observer": "2.1.3",
"@solid-primitives/scroll": "2.1.3",
"@solid-primitives/storage": "4.3.3",
"@solidjs/meta": "catalog:",
"@solidjs/router": "0.15.3",
"@thisbeyond/solid-dnd": "0.7.5",
@@ -150,7 +151,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.0.18",
"version": "1.0.44",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "22.0.0",
@@ -166,14 +167,14 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.0.18",
"version": "1.0.44",
"bin": {
"opencode": "./bin/opencode",
},
"dependencies": {
"@actions/core": "1.11.1",
"@actions/github": "6.0.1",
"@agentclientprotocol/sdk": "0.4.9",
"@agentclientprotocol/sdk": "0.5.1",
"@clack/prompts": "1.0.0-alpha.1",
"@hono/standard-validator": "0.1.5",
"@hono/zod-validator": "catalog:",
@@ -184,8 +185,8 @@
"@opencode-ai/plugin": "workspace:*",
"@opencode-ai/script": "workspace:*",
"@opencode-ai/sdk": "workspace:*",
"@opentui/core": "0.1.33",
"@opentui/solid": "0.1.33",
"@opentui/core": "0.1.38",
"@opentui/solid": "0.1.38",
"@parcel/watcher": "2.5.1",
"@pierre/precision-diffs": "catalog:",
"@solid-primitives/event-bus": "1.1.2",
@@ -207,6 +208,7 @@
"partial-json": "0.1.7",
"remeda": "catalog:",
"solid-js": "catalog:",
"strip-ansi": "7.1.2",
"tree-sitter-bash": "0.25.0",
"turndown": "7.2.0",
"ulid": "catalog:",
@@ -243,7 +245,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.0.18",
"version": "1.0.44",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"zod": "catalog:",
@@ -263,7 +265,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.0.18",
"version": "1.0.44",
"devDependencies": {
"@hey-api/openapi-ts": "0.81.0",
"@tsconfig/node22": "catalog:",
@@ -274,7 +276,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.0.18",
"version": "1.0.44",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@@ -287,7 +289,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.0.18",
"version": "1.0.44",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@@ -317,7 +319,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.0.18",
"version": "1.0.44",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
@@ -351,7 +353,6 @@
"trustedDependencies": [
"sharp",
"esbuild",
"tree-sitter",
"web-tree-sitter",
"tree-sitter-bash",
],
@@ -364,7 +365,7 @@
"@hono/zod-validator": "0.4.2",
"@kobalte/core": "0.13.11",
"@openauthjs/openauth": "0.0.0-20250322224806",
"@pierre/precision-diffs": "0.4.1",
"@pierre/precision-diffs": "0.4.4",
"@solidjs/meta": "0.29.4",
"@tailwindcss/vite": "4.1.11",
"@tsconfig/bun": "1.0.9",
@@ -401,7 +402,7 @@
"@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="],
"@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.4.9", "", { "dependencies": { "zod": "^3.0.0" } }, "sha512-ExwH828LaTGoTTjxuw49l+fwOLA+Yx0+qkWn1TcHMOsY5mVI9CUfkj7ZDhv2klgZ7mJeT+lxX/Dn/KINv1AkNQ=="],
"@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.5.1", "", { "dependencies": { "zod": "^3.0.0" } }, "sha512-9bq2TgjhLBSUSC5jE04MEe+Hqw8YePzKghhYZ9QcjOyonY3q2oJfX6GoSO83hURpEnsqEPIrex6VZN3+61fBJg=="],
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@2.2.10", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-icLGO7Q0NinnHIPgT+y1QjHVwH4HwV+brWbvM+FfCG2Afpa89PyKa3Ret91kGjZpBgM/xnj1B7K5eM+rRlsXQA=="],
@@ -571,7 +572,7 @@
"@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="],
"@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.7.8", "", { "peerDependencies": { "unenv": "2.0.0-rc.21", "workerd": "^1.20250927.0" }, "optionalPeers": ["workerd"] }, "sha512-Ky929MfHh+qPhwCapYrRPwPVHtA2Ioex/DbGZyskGyNRDe9Ru3WThYZivyNVaPy5ergQSgMs9OKrM9Ajtz9F6w=="],
"@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.7.9", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": "^1.20250927.0" }, "optionalPeers": ["workerd"] }, "sha512-Drm7qlTKnvncEv+DANiQNEonq0H0LyIsoFZYJ6tJ8OhAoy5udIE8yp6BsVDYcIjcYLIybp4M7c/P7ly/56SoHg=="],
"@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20251011.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-0DirVP+Z82RtZLlK2B+VhLOkk+ShBqDYO/jhcRw4oVlp0TOvk3cOVZChrt3+y3NV8Y/PYgTEywzLKFSziK4wCg=="],
@@ -601,7 +602,7 @@
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="],
"@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="],
"@emnapi/runtime": ["@emnapi/runtime@1.7.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q=="],
"@emotion/is-prop-valid": ["@emotion/is-prop-valid@0.8.8", "", { "dependencies": { "@emotion/memoize": "0.7.4" } }, "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA=="],
@@ -611,57 +612,57 @@
"@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.11", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.11", "", { "os": "android", "cpu": "arm" }, "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.11", "", { "os": "android", "cpu": "arm64" }, "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.11", "", { "os": "android", "cpu": "x64" }, "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.11", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.11", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.11", "", { "os": "linux", "cpu": "arm" }, "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.11", "", { "os": "linux", "cpu": "ia32" }, "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.11", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.11", "", { "os": "linux", "cpu": "s390x" }, "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.11", "", { "os": "linux", "cpu": "x64" }, "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.11", "", { "os": "none", "cpu": "x64" }, "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.11", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.11", "", { "os": "openbsd", "cpu": "x64" }, "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.11", "", { "os": "sunos", "cpu": "x64" }, "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.11", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.11", "", { "os": "win32", "cpu": "x64" }, "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
"@expressive-code/core": ["@expressive-code/core@0.41.3", "", { "dependencies": { "@ctrl/tinycolor": "^4.0.4", "hast-util-select": "^6.0.2", "hast-util-to-html": "^9.0.1", "hast-util-to-text": "^4.0.1", "hastscript": "^9.0.0", "postcss": "^8.4.38", "postcss-nested": "^6.0.1", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1" } }, "sha512-9qzohqU7O0+JwMEEgQhnBPOw5DtsQRBXhW++5fvEywsuX44vCGGof1SL5OvPElvNgaWZ4pFZAFSlkNOkGyLwSQ=="],
@@ -961,21 +962,21 @@
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
"@opentui/core": ["@opentui/core@0.1.33", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.33", "@opentui/core-darwin-x64": "0.1.33", "@opentui/core-linux-arm64": "0.1.33", "@opentui/core-linux-x64": "0.1.33", "@opentui/core-win32-arm64": "0.1.33", "@opentui/core-win32-x64": "0.1.33", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-vwHdrPIqnsY6YnG2JTNhenHSsx+HUPYrQTBZdmEfCj9ROGVzKgUKbSDH1xGK2OtSNRb2KVBg4XaMpq0bie6afQ=="],
"@opentui/core": ["@opentui/core@0.1.38", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.38", "@opentui/core-darwin-x64": "0.1.38", "@opentui/core-linux-arm64": "0.1.38", "@opentui/core-linux-x64": "0.1.38", "@opentui/core-win32-arm64": "0.1.38", "@opentui/core-win32-x64": "0.1.38", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-GwSsOfGos0CTJhVaCT9DSGM/VcM38Kj8Ds06+sfloxB4sxPgrkItfXxwIm2uCLGUAtuGgGGUN8nMfUmrTibKZw=="],
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.33", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JBvzcP2V7fT9KxFAMenHRd/t72qPP5IL5kzge2uok1T7t2nw3Wa+CWI5s6FYP42p2b1W9qZkv5Fno5gA7OAYuQ=="],
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.38", "", { "os": "darwin", "cpu": "arm64" }, "sha512-iC71iR1N1ZiHjTC84PbncD7+NC1a+hWdF+wK7DVpW0NsKFRhNImIKGFxoq9aAG+/mH1dcvyNmk29gBwQnbPSpg=="],
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.33", "", { "os": "darwin", "cpu": "x64" }, "sha512-x7DY6VCkAky10z/2o4UkkuNW/nIvoX7uAh3dJOHWZCLbiKywSFvFk3QZVVcH5BMk4tOOophYTzika4s4HpaeMg=="],
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.38", "", { "os": "darwin", "cpu": "x64" }, "sha512-5f68CY8VC6/W78FjaeP/B/K6L5R28M+ypyZMzZphssimUAXY2uXzJyXN4AMSRWnI9ztDb1XS54m1GWkB2MBLGw=="],
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.33", "", { "os": "linux", "cpu": "arm64" }, "sha512-bBc1EdkVxsLBtqGjXM2BYpBJLa57ogcrSADSZbc5cQkPu0muSGzUwBbVnVZJUjWEfk6n5jcd4dDmLezVoQga0A=="],
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.38", "", { "os": "linux", "cpu": "arm64" }, "sha512-WNiI7jx6o7UYCPNtp05ajODPSzQLZN2+DADKBWT3pOwGpWvLYeMQpUGYQ0Z1nmwsqO5R/27SJdaoPnbKU6DIPw=="],
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.33", "", { "os": "linux", "cpu": "x64" }, "sha512-3oVL5mrLlKLUc1lc4v7xS3BJ9N7PnnimbGwAvlnVpfaAygotAs1XkPcjsUe6ItMnSJyi0FWiDHUE2+GiDtM5Nw=="],
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.38", "", { "os": "linux", "cpu": "x64" }, "sha512-sjQlgbmY0QNIyaCUO/Qp8J7wLLrTjhFzrQQE50Q4ReTNC6puUgsNBlT4PxoS3bYxVtvHYr+y95OCRqZPrbkyrQ=="],
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.33", "", { "os": "win32", "cpu": "arm64" }, "sha512-Q68v7wssE+r0OG1KIGfi7m3fnu8KOK4ZNg9ML6EwE47VF9/bqgUe+6fPiXh5mmHzTwof7nAOdXCf052av5/upQ=="],
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.38", "", { "os": "win32", "cpu": "arm64" }, "sha512-mFylg8AItMvWaf4YhUfrO72NIrArjY3zhmHXObnV2pssvWZQWmskvtLPaXoaOEAyRBbev5hx7h58DgVzq6ECqw=="],
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.33", "", { "os": "win32", "cpu": "x64" }, "sha512-PvuchmUnbMCUXXMzfle/WTzhNGIdJ6RGCCoclx3YVUyNUVuUicPf42OEV+td2m81/Hr3CgcLn98HYX1TLIzPrw=="],
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.38", "", { "os": "win32", "cpu": "x64" }, "sha512-5JmYrlmT1OlLI8eAdSW7r4m1J903c15VtkfLOkjEpqasvS75J0ulvq6kuofdqXuYqBarIh8cb8lcsTFQJniM2Q=="],
"@opentui/solid": ["@opentui/solid@0.1.33", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.33", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-bWSALdGJ2j51zwZ2gK1ZIBxFgauHq+V1ejEnyd4XamYMdWfpAKU+AUWDVLbpx1T9XG1oAnycJZfYX7BsZdVOOg=="],
"@opentui/solid": ["@opentui/solid@0.1.38", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.38", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-xkBmuVEvpSddryzgGS7Y7KoP3UKiRbKcW7T9vlMrYQwq+JhqGuKsG0RI0wpG2kv6gTYeU1/OkwYzPm1DjXBaoA=="],
"@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
@@ -1033,7 +1034,7 @@
"@petamoriken/float16": ["@petamoriken/float16@3.9.3", "", {}, "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g=="],
"@pierre/precision-diffs": ["@pierre/precision-diffs@0.4.1", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-AoozHakINGyNJFgbYc/1PlDK0yunrAxbtXEMBe9fdu8RLkNjVtYRTLw7EF2mM/YuVoVRjj2HT/2VJ4a2rMyDOA=="],
"@pierre/precision-diffs": ["@pierre/precision-diffs@0.4.4", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/transformers": "3.14.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.14.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-9bhWs+hsz1i0/SMIrzce+fFrSec8aLIFrJYTGHATlynmQovngIWz1Gc+XwGigvY4+zSMksrGPzO5HiaNlvRqtQ=="],
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
@@ -1041,7 +1042,7 @@
"@poppinss/colors": ["@poppinss/colors@4.1.5", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw=="],
"@poppinss/dumper": ["@poppinss/dumper@0.6.4", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-iG0TIdqv8xJ3Lt9O8DrPRxw1MRLjNpoqiSGU03P/wNLP/s0ra0udPJ1J2Tx5M0J3H/cVyEgpbn8xUKRY9j59kQ=="],
"@poppinss/dumper": ["@poppinss/dumper@0.6.5", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw=="],
"@poppinss/exception": ["@poppinss/exception@1.2.2", "", {}, "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg=="],
@@ -1187,7 +1188,7 @@
"@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="],
"@sindresorhus/is": ["@sindresorhus/is@7.1.0", "", {}, "sha512-7F/yz2IphV39hiS2zB4QYVkivrptHHh0K8qJJd9HhuWSdvf8AN7NpebW3CcDZDBQsUPMoDKWsY2WWgW7bqOcfA=="],
"@sindresorhus/is": ["@sindresorhus/is@7.1.1", "", {}, "sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ=="],
"@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="],
@@ -1205,7 +1206,7 @@
"@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
"@smithy/config-resolver": ["@smithy/config-resolver@4.4.1", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-BciDJ5hkyYEGBBKMbjGB1A/Zq8bYZ41Zo9BMnGdKF6QD1fY4zIkYx6zui/0CHaVGnv6h0iy8y4rnPX9CPCAPyQ=="],
"@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
"@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
@@ -1267,7 +1268,7 @@
"@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
"@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.7", "", { "dependencies": { "@smithy/config-resolver": "^4.4.1", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-6hinjVqec0WYGsqN7h9hL/ywfULmJJNXGXnNZW7jrIn/cFuC/aVlVaiDfBIJEvKcOrmN8/EgsW69eY0gXABeHw=="],
"@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
"@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
@@ -1309,6 +1310,8 @@
"@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="],
"@solid-primitives/storage": ["@solid-primitives/storage@4.3.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "@tauri-apps/plugin-store": "*", "solid-js": "^1.6.12" }, "optionalPeers": ["@tauri-apps/plugin-store"] }, "sha512-ACbNwMZ1s8VAvld6EUXkDkX/US3IhtlPLxg6+B2s9MwNUugwdd51I98LPEaHrdLpqPmyzqgoJe0TxEFlf3Dqrw=="],
"@solid-primitives/trigger": ["@solid-primitives/trigger@1.2.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-IWoptVc0SWYgmpBPpCMehS5b07+tpFcvw15tOQ3QbXedSYn6KP8zCjPkHNzMxcOvOicTneleeZDP7lqmz+PQ6g=="],
"@solid-primitives/utils": ["@solid-primitives/utils@6.3.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-hZ/M/qr25QOCcwDPOHtGjxTD8w2mNyVAYvcfgwzBHq2RwNqHNdDNsMZYap20+ruRwW4A3Cdkczyoz0TSxLCAPQ=="],
@@ -1319,7 +1322,7 @@
"@solidjs/start": ["@solidjs/start@1.2.0", "", { "dependencies": { "@tanstack/server-functions-plugin": "1.121.21", "@vinxi/plugin-directives": "^0.5.0", "@vinxi/server-components": "^0.5.0", "cookie-es": "^2.0.0", "defu": "^6.1.2", "error-stack-parser": "^2.1.4", "html-to-image": "^1.11.11", "radix3": "^1.1.0", "seroval": "^1.0.2", "seroval-plugins": "^1.0.2", "shiki": "^1.26.1", "source-map-js": "^1.0.2", "terracotta": "^1.0.4", "tinyglobby": "^0.2.2", "vite-plugin-solid": "^2.11.1" }, "peerDependencies": { "vinxi": "^0.5.7" } }, "sha512-SRv1g3R+4sxZnxCBPK1IedtLKsPhPJ7W/Yv4xEHjM4jJGPWi3ed35/yd0D5zhRK0C7zJIkZKbhnR/S3g8JUD5w=="],
"@speed-highlight/core": ["@speed-highlight/core@1.2.8", "", {}, "sha512-IGytNtnUnPIobIbOq5Y6LIlqiHNX+vnToQIS7lj6L5819C+rA8TXRDkkG8vePsiBOGcoW9R6i+dp2YBUKdB09Q=="],
"@speed-highlight/core": ["@speed-highlight/core@1.2.12", "", {}, "sha512-uilwrK0Ygyri5dToHYdZSjcvpS2ZwX0w5aSt3GCEN9hrjxWCoeV4Z2DTXuxjwbntaLQIEEAlCeNQss5SoHvAEA=="],
"@standard-community/standard-json": ["@standard-community/standard-json@0.3.5", "", { "peerDependencies": { "@standard-schema/spec": "^1.0.0", "@types/json-schema": "^7.0.15", "@valibot/to-json-schema": "^1.3.0", "arktype": "^2.1.20", "effect": "^3.16.8", "quansync": "^0.2.11", "sury": "^10.0.0", "typebox": "^1.0.17", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.24.5" }, "optionalPeers": ["@valibot/to-json-schema", "arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-to-json-schema"] }, "sha512-4+ZPorwDRt47i+O7RjyuaxHRK/37QY/LmgxlGrRrSTLYoFatEOzvqIc85GTlM18SFZ5E91C+v0o/M37wZPpUHA=="],
@@ -1447,7 +1450,7 @@
"@types/scheduler": ["@types/scheduler@0.26.0", "", {}, "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA=="],
"@types/send": ["@types/send@0.17.6", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og=="],
"@types/send": ["@types/send@1.2.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ=="],
"@types/serve-static": ["@types/serve-static@1.15.10", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw=="],
@@ -1589,7 +1592,7 @@
"aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="],
"axios": ["axios@1.13.1", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw=="],
"axios": ["axios@1.13.2", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA=="],
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
@@ -1617,13 +1620,13 @@
"bare-stream": ["bare-stream@2.7.0", "", { "dependencies": { "streamx": "^2.21.0" }, "peerDependencies": { "bare-buffer": "*", "bare-events": "*" }, "optionalPeers": ["bare-buffer", "bare-events"] }, "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A=="],
"bare-url": ["bare-url@2.3.1", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-v2yl0TnaZTdEnelkKtXZGnotiV6qATBlnNuUMrHl6v9Lmmrh9mw9RYyImPU7/4RahumSwQS1k2oKXcRfXcbjJw=="],
"bare-url": ["bare-url@2.3.2", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw=="],
"base-64": ["base-64@1.0.0", "", {}, "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="],
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.8.21", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-JU0h5APyQNsHOlAM7HnQnPToSDQoEBZqzu/YBlqDnEeymPnZDREeXJA3KBMQee+dKteAxZ2AtvQEvVYdZf241Q=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.8.25", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA=="],
"bcp-47": ["bcp-47@2.1.0", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w=="],
@@ -1701,7 +1704,7 @@
"camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="],
"caniuse-lite": ["caniuse-lite@1.0.30001752", "", {}, "sha512-vKUk7beoukxE47P5gcVNKkDRzXdVofotshHwfR9vmpeFKxmI5PBpgOMC18LUJUA/DvJ70Y7RveasIBraqsyO/g=="],
"caniuse-lite": ["caniuse-lite@1.0.30001753", "", {}, "sha512-Bj5H35MD/ebaOV4iDLqPEtiliTN29qkGtEHCwawWn4cYm+bPJM2NsaP30vtZcnERClMzp52J4+aw2UNbK4o+zw=="],
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
@@ -1919,7 +1922,7 @@
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
"electron-to-chromium": ["electron-to-chromium@1.5.244", "", {}, "sha512-OszpBN7xZX4vWMPJwB9illkN/znA8M36GQqQxi6MNy9axWxhOfJyZZJtSLQCpEFLHP2xK33BiWx9aIuIEXVCcw=="],
"electron-to-chromium": ["electron-to-chromium@1.5.245", "", {}, "sha512-rdmGfW47ZhL/oWEJAY4qxRtdly2B98ooTJ0pdEI4jhVLZ6tNf8fPtov2wS1IRKwFJT92le3x4Knxiwzl7cPPpQ=="],
"emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
@@ -1961,7 +1964,7 @@
"esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="],
"esbuild": ["esbuild@0.25.11", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.11", "@esbuild/android-arm": "0.25.11", "@esbuild/android-arm64": "0.25.11", "@esbuild/android-x64": "0.25.11", "@esbuild/darwin-arm64": "0.25.11", "@esbuild/darwin-x64": "0.25.11", "@esbuild/freebsd-arm64": "0.25.11", "@esbuild/freebsd-x64": "0.25.11", "@esbuild/linux-arm": "0.25.11", "@esbuild/linux-arm64": "0.25.11", "@esbuild/linux-ia32": "0.25.11", "@esbuild/linux-loong64": "0.25.11", "@esbuild/linux-mips64el": "0.25.11", "@esbuild/linux-ppc64": "0.25.11", "@esbuild/linux-riscv64": "0.25.11", "@esbuild/linux-s390x": "0.25.11", "@esbuild/linux-x64": "0.25.11", "@esbuild/netbsd-arm64": "0.25.11", "@esbuild/netbsd-x64": "0.25.11", "@esbuild/openbsd-arm64": "0.25.11", "@esbuild/openbsd-x64": "0.25.11", "@esbuild/openharmony-arm64": "0.25.11", "@esbuild/sunos-x64": "0.25.11", "@esbuild/win32-arm64": "0.25.11", "@esbuild/win32-ia32": "0.25.11", "@esbuild/win32-x64": "0.25.11" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q=="],
"esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
"esbuild-plugin-copy": ["esbuild-plugin-copy@2.1.1", "", { "dependencies": { "chalk": "^4.1.2", "chokidar": "^3.5.3", "fs-extra": "^10.0.1", "globby": "^11.0.3" }, "peerDependencies": { "esbuild": ">= 0.14.0" } }, "sha512-Bk66jpevTcV8KMFzZI1P7MZKZ+uDcrZm2G2egZ2jNIvVnivDpodZI+/KnpL3Jnap0PBdIHU7HwFGB8r+vV5CVw=="],
@@ -2665,7 +2668,7 @@
"mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
"miniflare": ["miniflare@4.20251011.1", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20251011.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-Qbw1Z8HTYM1adWl6FAtzhrj34/6dPRDPwdYOx21dkae8a/EaxbMzRIPbb4HKVGMVvtqbK1FaRCgDLVLolNzGHg=="],
"miniflare": ["miniflare@4.20251011.2", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20251011.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-5oAaz6lqZus4QFwzEJiNtgpjZR2TBVwBeIhOW33V4gu+l23EukpKja831tFIX2o6sOD/hqZmKZHplOrWl3YGtQ=="],
"minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="],
@@ -2749,11 +2752,11 @@
"object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="],
"ofetch": ["ofetch@1.5.0", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-A7llJ7eZyziA5xq9//3ZurA8OhFqtS99K5/V1sLBJ5j137CM/OAjlbA/TEJXBuOWwOfLqih+oH5U3ran4za1FQ=="],
"ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="],
"ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
"oidc-token-hash": ["oidc-token-hash@5.1.1", "", {}, "sha512-D7EmwxJV6DsEB6vOFLrBM2OzsVgQzgPWyHlV2OOAVj772n+WTXpudC9e9u5BVKQnYwaD30Ivhi9b+4UeBcGu9g=="],
"oidc-token-hash": ["oidc-token-hash@5.2.0", "", {}, "sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw=="],
"omggif": ["omggif@1.0.10", "", {}, "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="],
@@ -3175,23 +3178,23 @@
"sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="],
"sst": ["sst@3.17.19", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.19", "sst-darwin-x64": "3.17.19", "sst-linux-arm64": "3.17.19", "sst-linux-x64": "3.17.19", "sst-linux-x86": "3.17.19", "sst-win32-arm64": "3.17.19", "sst-win32-x64": "3.17.19", "sst-win32-x86": "3.17.19" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-j0FlQhFZW+QWCczzqfPr6fZAF0Um7lP1tbGdd7zkbjFlxdk9BUBI4CYXUnopC6KaTMtjvpfg3XRF7v0bDc9g+A=="],
"sst": ["sst@3.17.22", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.22", "sst-darwin-x64": "3.17.22", "sst-linux-arm64": "3.17.22", "sst-linux-x64": "3.17.22", "sst-linux-x86": "3.17.22", "sst-win32-arm64": "3.17.22", "sst-win32-x64": "3.17.22", "sst-win32-x86": "3.17.22" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-C+XMTbm6fx+7eT+ESAMATqG7qV7+pyVfxYQb6osdH3jd4u91QW1VU/xlEru+RU1rs1ZE58ixXdRP75UGPn+gog=="],
"sst-darwin-arm64": ["sst-darwin-arm64@3.17.19", "", { "os": "darwin", "cpu": "arm64" }, "sha512-6FeEgPqXkRT3o5qV0xktJ1eUiscJiPLBcGaxOxIEClpkVggZM83hO7Nizx/cAaAMhr1XQhbOZcKYueDHPdUY+Q=="],
"sst-darwin-arm64": ["sst-darwin-arm64@3.17.22", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B2pKq1dWc60+7HfXQ6/9etskxxNv9axxlQKveCLQAuG2a3mmtv2/jcR0Ch3mvSTGtW+KfhzUXda2kj7nZ/phBA=="],
"sst-darwin-x64": ["sst-darwin-x64@3.17.19", "", { "os": "darwin", "cpu": "x64" }, "sha512-/z78dxfLHG8FtOhpjMnYSpKSdQjfdyKbq+cL3eud2+g2BQr7IyQ8BWNGimk2oadh38V3r6dO1/5aVJh3x3l1rg=="],
"sst-darwin-x64": ["sst-darwin-x64@3.17.22", "", { "os": "darwin", "cpu": "x64" }, "sha512-flikYqXvhwwrS6x2FDOde+MQODHaZCIbUkVHYO3/gYo99rbAMQ8VpC/3LXnmnPEQkLOwWCSzLp4S4F9nG/PW2g=="],
"sst-linux-arm64": ["sst-linux-arm64@3.17.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-vbcMjiuLVxZ7352ajGlMqsS4J5AkAYvjLmsEALySUBVQhJUO9U7pk2P+Orfn702ZcO+6+NkGG9AL/g3K9EM1Tg=="],
"sst-linux-arm64": ["sst-linux-arm64@3.17.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-+pyD8Oej9js8XeCCebiEIde02vC5hc+bLl2/jR02K+9gYkGVJ6n5bkT8AlR8zWdS4FJKPyeJYUfjliT1T33j+g=="],
"sst-linux-x64": ["sst-linux-x64@3.17.19", "", { "os": "linux", "cpu": "x64" }, "sha512-gkNNmuHyvKjcb7RwMyoUH4wtgd7/bH7vUlMbcVsDzwt38y7+iTxyPMbcihucw42wDQRaDJtkDneSqj08U+MTFQ=="],
"sst-linux-x64": ["sst-linux-x64@3.17.22", "", { "os": "linux", "cpu": "x64" }, "sha512-A5p941edP9wgfgsbLUMeEPvi9JExj0OSaxgtFAC6/6BYoW4zruGAPzq206Ln6dNYP3gRdo5TJbSjio3F0ot8qg=="],
"sst-linux-x86": ["sst-linux-x86@3.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-Bsvunkh4onZRVv4Rxq7bT/63qQOg2KJoQKhAQtFkJdbri/cOA2QWkzqH8+pC5Sv9rSvbcIJAEIhMXILC0pqCJw=="],
"sst-linux-x86": ["sst-linux-x86@3.17.22", "", { "os": "linux", "cpu": "none" }, "sha512-pFDIi+ZwH8GOvy5He9wsbAjRGf/sTGhGE/V480w0A6itb9BC4jQ9sblJkk3Jx/fP2g27pKN2RNz+ifOU+GrUYQ=="],
"sst-win32-arm64": ["sst-win32-arm64@3.17.19", "", { "os": "win32", "cpu": "arm64" }, "sha512-dKxR4v24AODJLHiT9yNena0JUgyz3cHyCi6HZyxyG3dXyWncMe1ZXMXIgs1ZEUcU4XeYM2HVy+Nnz4KB1US1Kg=="],
"sst-win32-arm64": ["sst-win32-arm64@3.17.22", "", { "os": "win32", "cpu": "arm64" }, "sha512-9KaIrk+Z6hLDNi9GShf9NLrZi9jC/NNGpUAn6HvTXr8c6HUyQzg6takMH8nrISGCPn92y+IYWqdglaqbgnJTog=="],
"sst-win32-x64": ["sst-win32-x64@3.17.19", "", { "os": "win32", "cpu": "x64" }, "sha512-zgxSkGWZ1dewAr4R3slN/d3X9yumQDvAUOlJiX/6QE9Z67t/XNlow4+5i3L2oz4WHAFi59Un12YxbfM+RsBDmA=="],
"sst-win32-x64": ["sst-win32-x64@3.17.22", "", { "os": "win32", "cpu": "x64" }, "sha512-cvzyet4octGHK7w05jPUSPmUdlAWyh8IzjB8Pcs873K9AUGJEtQCftOKZjXaFdIG9DTvFWCCBi9zdzClxT9jJg=="],
"sst-win32-x86": ["sst-win32-x86@3.17.19", "", { "os": "win32", "cpu": "none" }, "sha512-z8S0kyb0ibz9Q3cNYDpcKYX47jys7j/mdebC8HUhtED1qKEAfqQ1vsR+zvWyN64Z9Ijj7aPi1KwNV6Et3d7F8g=="],
"sst-win32-x86": ["sst-win32-x86@3.17.22", "", { "os": "win32", "cpu": "none" }, "sha512-ol5icDJuHzG+AjbGbCIQoF8z3oiikTF9CtccdK/udqEF861DnngWzM99IY5TJvmJlN+38yOV0MY4XI5hM6SEQA=="],
"stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="],
@@ -3243,7 +3246,7 @@
"strtok3": ["strtok3@6.3.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^4.1.0" } }, "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw=="],
"style-to-js": ["style-to-js@1.1.18", "", { "dependencies": { "style-to-object": "1.0.11" } }, "sha512-JFPn62D4kJaPTnhFUI244MThx+FEGbi+9dw1b9yBBQ+1CZpV7QAT8kUtJ7b7EUNdHajjF/0x8fT+16oLJoojLg=="],
"style-to-js": ["style-to-js@1.1.19", "", { "dependencies": { "style-to-object": "1.0.12" } }, "sha512-Ev+SgeqiNGT1ufsXyVC5RrJRXdrkRJ1Gol9Qw7Pb72YCKJXrBvP0ckZhBeVSrw2m06DJpei2528uIpjMb4TsoQ=="],
"style-to-object": ["style-to-object@1.0.12", "", { "dependencies": { "inline-style-parser": "0.2.6" } }, "sha512-ddJqYnoT4t97QvN2C95bCgt+m7AAgXjVnkk/jxAfmp7EAB8nnqqZYEbMd3em7/vEomDb2LAQKAy1RFfv41mdNw=="],
@@ -3271,7 +3274,7 @@
"terracotta": ["terracotta@1.0.6", "", { "dependencies": { "solid-use": "^0.9.0" }, "peerDependencies": { "solid-js": "^1.8" } }, "sha512-yVrmT/Lg6a3tEbeYEJH8ksb1PYkR5FA9k5gr1TchaSNIiA2ZWs5a+koEbePXwlBP0poaV7xViZ/v50bQFcMgqw=="],
"terser": ["terser@5.44.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w=="],
"terser": ["terser@5.44.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw=="],
"text-decoder": ["text-decoder@1.2.3", "", { "dependencies": { "b4a": "^1.6.4" } }, "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA=="],
@@ -3305,8 +3308,6 @@
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
"tree-sitter": ["tree-sitter@0.25.0", "", { "dependencies": { "node-addon-api": "^8.3.0", "node-gyp-build": "^4.8.4" } }, "sha512-PGZZzFW63eElZJDe/b/R/LbsjDDYJa5UEjLZJB59RQsMX+fo0j54fqBPn1MGKav/QNa0JR0zBiVaikYDWCj5KQ=="],
"tree-sitter-bash": ["tree-sitter-bash@0.25.0", "", { "dependencies": { "node-addon-api": "^8.2.1", "node-gyp-build": "^4.8.2" }, "peerDependencies": { "tree-sitter": "^0.25.0" }, "optionalPeers": ["tree-sitter"] }, "sha512-gZtlj9+qFS81qKxpLfD6H0UssQ3QBc/F0nKkPsiFDyfQF2YBqYvglFJUzchrPpVhZe9kLZTrJ9n2J6lmka69Vg=="],
"trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
@@ -3421,7 +3422,7 @@
"unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="],
"unstorage": ["unstorage@1.17.1", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.4.1", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-KKGwRTT0iVBCErKemkJCLs7JdxNVfqTPc/85ae1XES0+bsHbc/sFBfVi5kJp156cc51BHinIH2l3k0EZ24vOBQ=="],
"unstorage": ["unstorage@1.17.2", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.0", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-cKEsD6iBWJgOMJ6vW1ID/SYuqNf8oN4yqRk8OYqaVQ3nnkJXOT1PSpaMh2QfzLs78UN5kSNRD2c/mgjT8tX7+w=="],
"untun": ["untun@0.1.3", "", { "dependencies": { "citty": "^0.1.5", "consola": "^3.2.3", "pathe": "^1.1.1" }, "bin": { "untun": "bin/untun.mjs" } }, "sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ=="],
@@ -3507,7 +3508,7 @@
"workerd": ["workerd@1.20251011.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20251011.0", "@cloudflare/workerd-darwin-arm64": "1.20251011.0", "@cloudflare/workerd-linux-64": "1.20251011.0", "@cloudflare/workerd-linux-arm64": "1.20251011.0", "@cloudflare/workerd-windows-64": "1.20251011.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-Dq35TLPEJAw7BuYQMkN3p9rge34zWMU2Gnd4DSJFeVqld4+DAO2aPG7+We2dNIAyM97S8Y9BmHulbQ00E0HC7Q=="],
"wrangler": ["wrangler@4.45.3", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.7.8", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20251011.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.21", "workerd": "1.20251011.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20251011.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-0ddEA9t4HeBgSVTVTcqtBHl7Z5CorWZ8tGgTQCP5XuL+9E1TJRwS6t/zzG51Ruwjb17SZYCaLchoM8V629S8cw=="],
"wrangler": ["wrangler@4.45.4", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.7.9", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20251011.2", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20251011.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20251011.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-niXT7B463wQi7WXIHjYK8txgWhuKQLrGmhjoR58SnPhlkq4wGjd3rFrkVyRc/O58clGTfs672BSGOph4XMoQKw=="],
"wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="],
@@ -3545,7 +3546,7 @@
"yoga-layout": ["yoga-layout@3.2.1", "", {}, "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ=="],
"youch": ["youch@4.1.0-beta.11", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.4", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.3" } }, "sha512-sQi6PERyO/mT8w564ojOVeAlYTtVQmC2GaktQAf+IdI75/GKIggosBuvyVXvEV+FATAT6RbLdIjFoiIId4ozoQ=="],
"youch": ["youch@4.1.0-beta.12", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.5", "@speed-highlight/core": "^1.2.9", "cookie-es": "^2.0.0", "youch-core": "^0.3.3" } }, "sha512-X+AQ2EdigcZb2h1XQmBMm19TrrfKXxEXWpnf8ThbARwiiSf/pA7MvRTCj5VHCI9z3vjJBsDeqWWyvaI9Bfp9Pg=="],
"youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="],
@@ -3589,6 +3590,8 @@
"@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="],
"@astrojs/markdown-remark/shiki": ["shiki@3.14.0", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/engine-javascript": "3.14.0", "@shikijs/engine-oniguruma": "3.14.0", "@shikijs/langs": "3.14.0", "@shikijs/themes": "3.14.0", "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-J0yvpLI7LSig3Z3acIuDLouV5UCKQqu8qOArwMx+/yPVC3WRMgrP67beaG8F+j4xfEWE0eVC4GeBCIXeOPra1g=="],
"@astrojs/mdx/@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.8", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.4", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.13.0", "smol-toml": "^1.4.2", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1", "vfile": "^6.0.3" } }, "sha512-uFNyFWadnULWK2cOw4n0hLKeu+xaVWeuECdP10cQ3K2fkybtTlhb7J7TcScdjmS8Yps7oje9S/ehYMfZrhrgCg=="],
"@astrojs/sitemap/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
@@ -3609,13 +3612,13 @@
"@cloudflare/kv-asset-handler/mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
"@cloudflare/unenv-preset/unenv": ["unenv@2.0.0-rc.21", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A=="],
"@cloudflare/unenv-preset/unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="],
"@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="],
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
"@expressive-code/plugin-shiki/shiki": ["shiki@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/engine-javascript": "3.13.0", "@shikijs/engine-oniguruma": "3.13.0", "@shikijs/langs": "3.13.0", "@shikijs/themes": "3.13.0", "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g=="],
"@expressive-code/plugin-shiki/shiki": ["shiki@3.14.0", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/engine-javascript": "3.14.0", "@shikijs/engine-oniguruma": "3.14.0", "@shikijs/langs": "3.14.0", "@shikijs/themes": "3.14.0", "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-J0yvpLI7LSig3Z3acIuDLouV5UCKQqu8qOArwMx+/yPVC3WRMgrP67beaG8F+j4xfEWE0eVC4GeBCIXeOPra1g=="],
"@hono/zod-validator/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
@@ -3725,11 +3728,11 @@
"@parcel/watcher-wasm/napi-wasm": ["napi-wasm@1.1.3", "", { "bundled": true }, "sha512-h/4nMGsHjZDCYmQVNODIrYACVJ+I9KItbG+0si6W/jSjdA9JbWDoU4LLeMXVcEQGHjttI2tuXqDrbGF7qkUHHg=="],
"@pierre/precision-diffs/@shikijs/core": ["@shikijs/core@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA=="],
"@pierre/precision-diffs/@shikijs/core": ["@shikijs/core@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-qRSeuP5vlYHCNUIrpEBQFO7vSkR7jn7Kv+5X3FO/zBKVDGQbcnlScD3XhkrHi/R8Ltz0kEjvFR9Szp/XMRbFMw=="],
"@pierre/precision-diffs/@shikijs/transformers": ["@shikijs/transformers@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/types": "3.13.0" } }, "sha512-833lcuVzcRiG+fXvgslWsM2f4gHpjEgui1ipIknSizRuTgMkNZupiXE5/TVJ6eSYfhNBFhBZKkReKWO2GgYmqA=="],
"@pierre/precision-diffs/@shikijs/transformers": ["@shikijs/transformers@3.14.0", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/types": "3.14.0" } }, "sha512-i67zQnY9wLMMnKasonVW1L9fKneSLZDj1ePsA4o0AZWU4uUobmJY9baRDa36z+a9/g0aG76/2tybQvm4hrwxIQ=="],
"@pierre/precision-diffs/shiki": ["shiki@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/engine-javascript": "3.13.0", "@shikijs/engine-oniguruma": "3.13.0", "@shikijs/langs": "3.13.0", "@shikijs/themes": "3.13.0", "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g=="],
"@pierre/precision-diffs/shiki": ["shiki@3.14.0", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/engine-javascript": "3.14.0", "@shikijs/engine-oniguruma": "3.14.0", "@shikijs/langs": "3.14.0", "@shikijs/themes": "3.14.0", "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-J0yvpLI7LSig3Z3acIuDLouV5UCKQqu8qOArwMx+/yPVC3WRMgrP67beaG8F+j4xfEWE0eVC4GeBCIXeOPra1g=="],
"@poppinss/dumper/supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="],
@@ -3757,9 +3760,9 @@
"@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.6.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.7.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
@@ -3775,6 +3778,8 @@
"@tanstack/server-functions-plugin/@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="],
"@types/serve-static/@types/send": ["@types/send@0.17.6", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og=="],
"@vercel/nft/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"@vercel/nft/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
@@ -3801,10 +3806,10 @@
"astro/diff": ["diff@5.2.0", "", {}, "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A=="],
"astro/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"astro/sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="],
"astro/shiki": ["shiki@3.14.0", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/engine-javascript": "3.14.0", "@shikijs/engine-oniguruma": "3.14.0", "@shikijs/langs": "3.14.0", "@shikijs/themes": "3.14.0", "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-J0yvpLI7LSig3Z3acIuDLouV5UCKQqu8qOArwMx+/yPVC3WRMgrP67beaG8F+j4xfEWE0eVC4GeBCIXeOPra1g=="],
"astro/vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
"astro/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
@@ -3849,7 +3854,7 @@
"dir-glob/path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
"dot-prop/type-fest": ["type-fest@5.1.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-wQ531tuWvB6oK+pchHIu5lHe5f5wpSCqB8Kf4dWQRbOYc9HTge7JL0G4Qd44bh6QuJCccIzL3bugb8GI0MwHrg=="],
"dot-prop/type-fest": ["type-fest@5.2.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-xxCJm+Bckc6kQBknN7i9fnP/xobQRsRQxR01CztFkp/h++yfVxUUcmMgfR2HttJx/dpWjS9ubVuyspJv24Q9DA=="],
"drizzle-kit/esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="],
@@ -3885,8 +3890,6 @@
"gaxios/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
"gel/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"giget/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"giget/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
@@ -4029,9 +4032,7 @@
"send/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="],
"sharp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"sitemap/sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="],
"sitemap/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="],
"source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
@@ -4047,8 +4048,6 @@
"strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],
"style-to-js/style-to-object": ["style-to-object@1.0.11", "", { "dependencies": { "inline-style-parser": "0.2.4" } }, "sha512-5A560JmXr7wDyGLK12Nq/EYS38VkGlglVzkis1JEdbGWSnbQIEhZzTJhzURXN5/8WwwFCs/f/VVcmkTppbXLow=="],
"sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
"sucrase/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
@@ -4059,8 +4058,6 @@
"token-types/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"tree-sitter/node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="],
"tree-sitter-bash/node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="],
"tw-to-css/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
@@ -4097,7 +4094,7 @@
"wrangler/esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="],
"wrangler/unenv": ["unenv@2.0.0-rc.21", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A=="],
"wrangler/unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="],
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
@@ -4133,11 +4130,23 @@
"@actions/github/@octokit/request-error/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
"@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/core@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-qRSeuP5vlYHCNUIrpEBQFO7vSkR7jn7Kv+5X3FO/zBKVDGQbcnlScD3XhkrHi/R8Ltz0kEjvFR9Szp/XMRbFMw=="],
"@astrojs/markdown-remark/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-3v1kAXI2TsWQuwv86cREH/+FK9Pjw3dorVEykzQDhwrZj0lwsHYlfyARaKmn6vr5Gasf8aeVpb8JkzeWspxOLQ=="],
"@astrojs/markdown-remark/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug=="],
"@astrojs/markdown-remark/shiki/@shikijs/langs": ["@shikijs/langs@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg=="],
"@astrojs/markdown-remark/shiki/@shikijs/themes": ["@shikijs/themes@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA=="],
"@astrojs/markdown-remark/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="],
"@astrojs/mdx/@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.7.4", "", {}, "sha512-lDA9MqE8WGi7T/t2BMi+EAXhs4Vcvr94Gqx3q15cFEz8oFZMO4/SFBqYr/UcmNlvW+35alowkVj+w9VhLvs5Cw=="],
"@astrojs/mdx/@astrojs/markdown-remark/@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki": ["shiki@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/engine-javascript": "3.13.0", "@shikijs/engine-oniguruma": "3.13.0", "@shikijs/langs": "3.13.0", "@shikijs/themes": "3.13.0", "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki": ["shiki@3.14.0", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/engine-javascript": "3.14.0", "@shikijs/engine-oniguruma": "3.14.0", "@shikijs/langs": "3.14.0", "@shikijs/themes": "3.14.0", "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-J0yvpLI7LSig3Z3acIuDLouV5UCKQqu8qOArwMx+/yPVC3WRMgrP67beaG8F+j4xfEWE0eVC4GeBCIXeOPra1g=="],
"@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
@@ -4191,17 +4200,17 @@
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
"@expressive-code/plugin-shiki/shiki/@shikijs/core": ["@shikijs/core@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA=="],
"@expressive-code/plugin-shiki/shiki/@shikijs/core": ["@shikijs/core@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-qRSeuP5vlYHCNUIrpEBQFO7vSkR7jn7Kv+5X3FO/zBKVDGQbcnlScD3XhkrHi/R8Ltz0kEjvFR9Szp/XMRbFMw=="],
"@expressive-code/plugin-shiki/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg=="],
"@expressive-code/plugin-shiki/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-3v1kAXI2TsWQuwv86cREH/+FK9Pjw3dorVEykzQDhwrZj0lwsHYlfyARaKmn6vr5Gasf8aeVpb8JkzeWspxOLQ=="],
"@expressive-code/plugin-shiki/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg=="],
"@expressive-code/plugin-shiki/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug=="],
"@expressive-code/plugin-shiki/shiki/@shikijs/langs": ["@shikijs/langs@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ=="],
"@expressive-code/plugin-shiki/shiki/@shikijs/langs": ["@shikijs/langs@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg=="],
"@expressive-code/plugin-shiki/shiki/@shikijs/themes": ["@shikijs/themes@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg=="],
"@expressive-code/plugin-shiki/shiki/@shikijs/themes": ["@shikijs/themes@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA=="],
"@expressive-code/plugin-shiki/shiki/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="],
"@expressive-code/plugin-shiki/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="],
"@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
@@ -4327,19 +4336,19 @@
"@opentui/solid/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@pierre/precision-diffs/@shikijs/core/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="],
"@pierre/precision-diffs/@shikijs/core/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="],
"@pierre/precision-diffs/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="],
"@pierre/precision-diffs/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="],
"@pierre/precision-diffs/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg=="],
"@pierre/precision-diffs/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-3v1kAXI2TsWQuwv86cREH/+FK9Pjw3dorVEykzQDhwrZj0lwsHYlfyARaKmn6vr5Gasf8aeVpb8JkzeWspxOLQ=="],
"@pierre/precision-diffs/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg=="],
"@pierre/precision-diffs/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug=="],
"@pierre/precision-diffs/shiki/@shikijs/langs": ["@shikijs/langs@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ=="],
"@pierre/precision-diffs/shiki/@shikijs/langs": ["@shikijs/langs@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg=="],
"@pierre/precision-diffs/shiki/@shikijs/themes": ["@shikijs/themes@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg=="],
"@pierre/precision-diffs/shiki/@shikijs/themes": ["@shikijs/themes@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA=="],
"@pierre/precision-diffs/shiki/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="],
"@pierre/precision-diffs/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="],
"@slack/web-api/p-queue/eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="],
@@ -4379,6 +4388,20 @@
"archiver-utils/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
"astro/sharp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"astro/shiki/@shikijs/core": ["@shikijs/core@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-qRSeuP5vlYHCNUIrpEBQFO7vSkR7jn7Kv+5X3FO/zBKVDGQbcnlScD3XhkrHi/R8Ltz0kEjvFR9Szp/XMRbFMw=="],
"astro/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-3v1kAXI2TsWQuwv86cREH/+FK9Pjw3dorVEykzQDhwrZj0lwsHYlfyARaKmn6vr5Gasf8aeVpb8JkzeWspxOLQ=="],
"astro/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug=="],
"astro/shiki/@shikijs/langs": ["@shikijs/langs@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg=="],
"astro/shiki/@shikijs/themes": ["@shikijs/themes@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA=="],
"astro/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="],
"axios/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"babel-plugin-module-resolver/glob/minimatch": ["minimatch@8.0.4", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA=="],
@@ -4387,6 +4410,8 @@
"babel-plugin-module-resolver/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
"bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"c12/pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
@@ -4499,7 +4524,7 @@
"opencontrol/@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.24.5", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="],
"parse-bmfont-xml/xml2js/sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="],
"parse-bmfont-xml/xml2js/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="],
"pkg-up/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="],
@@ -4523,8 +4548,6 @@
"string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"style-to-js/style-to-object/inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="],
"sucrase/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
"sucrase/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
@@ -4607,17 +4630,17 @@
"@actions/github/@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/core@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/core@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-qRSeuP5vlYHCNUIrpEBQFO7vSkR7jn7Kv+5X3FO/zBKVDGQbcnlScD3XhkrHi/R8Ltz0kEjvFR9Szp/XMRbFMw=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-3v1kAXI2TsWQuwv86cREH/+FK9Pjw3dorVEykzQDhwrZj0lwsHYlfyARaKmn6vr5Gasf8aeVpb8JkzeWspxOLQ=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/langs": ["@shikijs/langs@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/langs": ["@shikijs/langs@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/themes": ["@shikijs/themes@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/themes": ["@shikijs/themes@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="],
"@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="],
"@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
@@ -4749,7 +4772,7 @@
"@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es/regex-recursion": ["regex-recursion@5.1.1", "", { "dependencies": { "regex": "^5.1.1", "regex-utilities": "^2.3.0" } }, "sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w=="],
"nitropack/c12/giget/nypm/tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="],
"nitropack/c12/giget/nypm/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
"opencontrol/@modelcontextprotocol/sdk/express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
+1 -1
View File
@@ -6,4 +6,4 @@
/// <reference path="../sst-env.d.ts" />
import "sst"
export {}
export {}
@@ -1,15 +1,15 @@
{
"keep": {
"days": true,
"amount": 14
},
"auditLog": "/home/thdxr/dev/projects/sst/opencode/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json",
"files": [
{
"date": 1759827172859,
"name": "/home/thdxr/dev/projects/sst/opencode/logs/mcp-puppeteer-2025-10-07.log",
"hash": "a3d98b26edd793411b968a0d24cfeee8332138e282023c3b83ec169d55c67f16"
}
],
"hashType": "sha256"
}
"keep": {
"days": true,
"amount": 14
},
"auditLog": "/home/thdxr/dev/projects/sst/opencode/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json",
"files": [
{
"date": 1759827172859,
"name": "/home/thdxr/dev/projects/sst/opencode/logs/mcp-puppeteer-2025-10-07.log",
"hash": "a3d98b26edd793411b968a0d24cfeee8332138e282023c3b83ec169d55c67f16"
}
],
"hashType": "sha256"
}
+2 -2
View File
@@ -28,7 +28,7 @@
"@tsconfig/bun": "1.0.9",
"@cloudflare/workers-types": "4.20251008.0",
"@openauthjs/openauth": "0.0.0-20250322224806",
"@pierre/precision-diffs": "0.4.1",
"@pierre/precision-diffs": "0.4.4",
"@solidjs/meta": "0.29.4",
"@tailwindcss/vite": "4.1.11",
"diff": "8.0.2",
@@ -52,7 +52,7 @@
"@tsconfig/bun": "catalog:",
"husky": "9.1.7",
"prettier": "3.6.2",
"sst": "3.17.19",
"sst": "3.17.22",
"turbo": "2.5.6"
},
"dependencies": {
+1 -1
View File
@@ -7,7 +7,7 @@
"dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev",
"build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json",
"start": "vinxi start",
"version": "1.0.18"
"version": "1.0.44"
},
"dependencies": {
"@ibm/plex": "6.4.1",
+4 -1
View File
@@ -12,7 +12,10 @@ export default function App() {
root={(props) => (
<MetaProvider>
<Title>opencode</Title>
<Meta name="description" content="opencode - The AI coding agent built for the terminal." />
<Meta
name="description"
content="OpenCode - The AI coding agent built for the terminal."
/>
<Suspense>{props.children}</Suspense>
</MetaProvider>
)}
@@ -77,4 +77,4 @@
background-color: var(--color-accent-alpha);
}
}
}
}
+4 -1
View File
@@ -13,7 +13,10 @@ export function Faq(props: ParentProps & { question: string }) {
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M12.5 11.5H19V12.5H12.5V19H11.5V12.5H5V11.5H11.5V5H12.5V11.5Z" fill="currentColor" />
<path
d="M12.5 11.5H19V12.5H12.5V19H11.5V12.5H5V11.5H11.5V5H12.5V11.5Z"
fill="currentColor"
/>
</svg>
<svg
data-slot="faq-icon-minus"
@@ -1,6 +1,7 @@
import { createAsync } from "@solidjs/router"
import { createMemo } from "solid-js"
import { github } from "~/lib/github"
import { config } from "~/config"
export function Footer() {
const githubData = createAsync(() => github())
@@ -10,13 +11,13 @@ export function Footer() {
notation: "compact",
compactDisplay: "short",
}).format(githubData()!.stars!)
: "25K",
: config.github.starsFormatted.compact,
)
return (
<footer data-component="footer">
<div data-slot="cell">
<a href="https://github.com/sst/opencode" target="_blank">
<a href={config.github.repoUrl} target="_blank">
GitHub <span>[{starCount()}]</span>
</a>
</div>
@@ -27,7 +28,7 @@ export function Footer() {
<a href="/discord">Discord</a>
</div>
<div data-slot="cell">
<a href="https://x.com/opencode">X</a>
<a href={config.social.twitter}>X</a>
</div>
</footer>
)
@@ -18,6 +18,7 @@ import { createMemo, Match, Show, Switch } from "solid-js"
import { createStore } from "solid-js/store"
import { github } from "~/lib/github"
import { createEffect, onCleanup } from "solid-js"
import { config } from "~/config"
import "./header-context-menu.css"
const isDarkMode = () => window.matchMedia("(prefers-color-scheme: dark)").matches
@@ -42,7 +43,7 @@ export function Header(props: { zen?: boolean }) {
notation: "compact",
compactDisplay: "short",
}).format(githubData()?.stars!)
: "29K",
: config.github.starsFormatted.compact,
)
const [store, setStore] = createStore({
@@ -148,7 +149,7 @@ export function Header(props: { zen?: boolean }) {
<nav data-component="nav-desktop">
<ul>
<li>
<a href="https://github.com/sst/opencode" target="_blank">
<a href={config.github.repoUrl} target="_blank">
GitHub <span>[{starCount()}]</span>
</a>
</li>
@@ -222,7 +223,7 @@ export function Header(props: { zen?: boolean }) {
<A href="/">Home</A>
</li>
<li>
<a href="https://github.com/sst/opencode" target="_blank">
<a href={config.github.repoUrl} target="_blank">
GitHub <span>[{starCount()}]</span>
</a>
</li>
+113 -20
View File
@@ -9,10 +9,23 @@ export function IconLogo(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
<path d="M13.7124 9.14333V4.5719H18.2838V9.14333H13.7124Z" fill="currentColor" />
<path d="M13.7124 13.7136V9.14221H18.2838V13.7136H13.7124Z" fill="currentColor" />
<path d="M0 18.2857V13.7142H4.57143V18.2857H0Z" fill="currentColor" fill-opacity="0.2" />
<rect width="4.57143" height="4.57143" transform="translate(4.57178 13.7141)" fill="currentColor" />
<path d="M4.57178 18.2855V13.7141H9.14321V18.2855H4.57178Z" fill="currentColor" fill-opacity="0.2" />
<rect
width="4.57143"
height="4.57143"
transform="translate(4.57178 13.7141)"
fill="currentColor"
/>
<path
d="M4.57178 18.2855V13.7141H9.14321V18.2855H4.57178Z"
fill="currentColor"
fill-opacity="0.2"
/>
<path d="M9.1438 18.2855V13.7141H13.7152V18.2855H9.1438Z" fill="currentColor" />
<path d="M13.7156 18.2855V13.7141H18.287V18.2855H13.7156Z" fill="currentColor" fill-opacity="0.2" />
<path
d="M13.7156 18.2855V13.7141H18.287V18.2855H13.7156Z"
fill="currentColor"
fill-opacity="0.2"
/>
<rect width="4.57143" height="4.57143" transform="translate(0 18.2859)" fill="currentColor" />
<path d="M0 22.8572V18.2858H4.57143V22.8572H0Z" fill="currentColor" fill-opacity="0.2" />
<rect
@@ -23,8 +36,16 @@ export function IconLogo(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
fill-opacity="0.2"
/>
<path d="M4.57178 22.8573V18.2859H9.14321V22.8573H4.57178Z" fill="currentColor" />
<path d="M9.1438 22.8573V18.2859H13.7152V22.8573H9.1438Z" fill="currentColor" fill-opacity="0.2" />
<path d="M13.7156 22.8573V18.2859H18.287V22.8573H13.7156Z" fill="currentColor" fill-opacity="0.2" />
<path
d="M9.1438 22.8573V18.2859H13.7152V22.8573H9.1438Z"
fill="currentColor"
fill-opacity="0.2"
/>
<path
d="M13.7156 22.8573V18.2859H18.287V22.8573H13.7156Z"
fill="currentColor"
fill-opacity="0.2"
/>
<path d="M0 27.4292V22.8578H4.57143V27.4292H0Z" fill="currentColor" />
<path d="M4.57178 27.4292V22.8578H9.14321V27.4292H4.57178Z" fill="currentColor" />
<path d="M9.1438 27.4276V22.8562H13.7152V27.4276H9.1438Z" fill="currentColor" />
@@ -40,9 +61,21 @@ export function IconLogo(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
<path d="M32.001 18.2855V13.7141H36.5724V18.2855H32.001Z" fill="currentColor" />
<path d="M36.5698 18.2855V13.7141H41.1413V18.2855H36.5698Z" fill="currentColor" />
<path d="M22.8572 22.8573V18.2859H27.4286V22.8573H22.8572Z" fill="currentColor" />
<path d="M27.4292 22.8573V18.2859H32.0006V22.8573H27.4292Z" fill="currentColor" fill-opacity="0.2" />
<path d="M32.001 22.8573V18.2859H36.5724V22.8573H32.001Z" fill="currentColor" fill-opacity="0.2" />
<path d="M36.5698 22.8573V18.2859H41.1413V22.8573H36.5698Z" fill="currentColor" fill-opacity="0.2" />
<path
d="M27.4292 22.8573V18.2859H32.0006V22.8573H27.4292Z"
fill="currentColor"
fill-opacity="0.2"
/>
<path
d="M32.001 22.8573V18.2859H36.5724V22.8573H32.001Z"
fill="currentColor"
fill-opacity="0.2"
/>
<path
d="M36.5698 22.8573V18.2859H41.1413V22.8573H36.5698Z"
fill="currentColor"
fill-opacity="0.2"
/>
<path d="M22.8572 27.4292V22.8578H27.4286V27.4292H22.8572Z" fill="currentColor" />
<path d="M27.4292 27.4276V22.8562H32.0006V27.4276H27.4292Z" fill="currentColor" />
<path d="M32.001 27.4276V22.8562H36.5724V27.4276H32.001Z" fill="currentColor" />
@@ -53,16 +86,40 @@ export function IconLogo(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
<path d="M45.7144 13.7136V9.14221H50.2858V13.7136H45.7144Z" fill="currentColor" />
<path d="M59.4299 13.7152V9.1438H64.0014V13.7152H59.4299Z" fill="currentColor" />
<path d="M45.7144 18.2855V13.7141H50.2858V18.2855H45.7144Z" fill="currentColor" />
<path d="M50.2861 18.2857V13.7142H54.8576V18.2857H50.2861Z" fill="currentColor" fill-opacity="0.2" />
<path d="M54.8579 18.2855V13.7141H59.4293V18.2855H54.8579Z" fill="currentColor" fill-opacity="0.2" />
<path
d="M50.2861 18.2857V13.7142H54.8576V18.2857H50.2861Z"
fill="currentColor"
fill-opacity="0.2"
/>
<path
d="M54.8579 18.2855V13.7141H59.4293V18.2855H54.8579Z"
fill="currentColor"
fill-opacity="0.2"
/>
<path d="M59.4299 18.2855V13.7141H64.0014V18.2855H59.4299Z" fill="currentColor" />
<path d="M45.7144 22.8573V18.2859H50.2858V22.8573H45.7144Z" fill="currentColor" />
<path d="M50.2861 22.8572V18.2858H54.8576V22.8572H50.2861Z" fill="currentColor" fill-opacity="0.2" />
<path d="M54.8579 22.8573V18.2859H59.4293V22.8573H54.8579Z" fill="currentColor" fill-opacity="0.2" />
<path
d="M50.2861 22.8572V18.2858H54.8576V22.8572H50.2861Z"
fill="currentColor"
fill-opacity="0.2"
/>
<path
d="M54.8579 22.8573V18.2859H59.4293V22.8573H54.8579Z"
fill="currentColor"
fill-opacity="0.2"
/>
<path d="M59.4299 22.8573V18.2859H64.0014V22.8573H59.4299Z" fill="currentColor" />
<path d="M45.7144 27.4292V22.8578H50.2858V27.4292H45.7144Z" fill="currentColor" />
<path d="M50.2861 27.4286V22.8572H54.8576V27.4286H50.2861Z" fill="currentColor" fill-opacity="0.2" />
<path d="M54.8579 27.4285V22.8571H59.4293V27.4285H54.8579Z" fill="currentColor" fill-opacity="0.2" />
<path
d="M50.2861 27.4286V22.8572H54.8576V27.4286H50.2861Z"
fill="currentColor"
fill-opacity="0.2"
/>
<path
d="M54.8579 27.4285V22.8571H59.4293V27.4285H54.8579Z"
fill="currentColor"
fill-opacity="0.2"
/>
<path d="M59.4299 27.4292V22.8578H64.0014V27.4292H59.4299Z" fill="currentColor" />
</svg>
)
@@ -70,7 +127,14 @@ export function IconLogo(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
export function IconCopy(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
return (
<svg {...props} width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
{...props}
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.75 8.75V2.75H21.25V15.25H15.25M15.25 8.75H2.75V21.25H15.25V8.75Z"
stroke="currentColor"
@@ -83,8 +147,20 @@ export function IconCopy(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
export function IconCheck(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
return (
<svg {...props} width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.75 15.0938L9 20.25L21.25 3.75" stroke="#03B000" stroke-width="2" stroke-linecap="square" />
<svg
{...props}
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2.75 15.0938L9 20.25L21.25 3.75"
stroke="#03B000"
stroke-width="2"
stroke-linecap="square"
/>
</svg>
)
}
@@ -113,7 +189,14 @@ export function IconStripe(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
export function IconChevron(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
return (
<svg {...props} width="8" height="6" viewBox="0 0 8 6" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
{...props}
width="8"
height="6"
viewBox="0 0 8 6"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="M4.00024 5.04041L7.37401 1.66663L6.66691 0.959525L4.00024 3.62619L1.33357 0.959525L0.626465 1.66663L4.00024 5.04041Z"
@@ -124,7 +207,14 @@ export function IconChevron(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
export function IconWorkspaceLogo(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
return (
<svg {...props} width="24" height="30" viewBox="0 0 24 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
{...props}
width="24"
height="30"
viewBox="0 0 24 30"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M18 6H6V24H18V6ZM24 30H0V0H24V30Z" fill="currentColor" />
</svg>
)
@@ -144,7 +234,10 @@ export function IconOpenAI(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
export function IconAnthropic(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
return (
<svg {...props} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" d="M13.7891 3.93188L20.2223 20.068H23.7502L17.317 3.93188H13.7891Z" />
<path
fill="currentColor"
d="M13.7891 3.93188L20.2223 20.068H23.7502L17.317 3.93188H13.7891Z"
/>
<path
fill="currentColor"
d="M6.32538 13.6827L8.52662 8.01201L10.7279 13.6827H6.32538ZM6.68225 3.93188L0.25 20.068H3.84652L5.16202 16.6794H11.8914L13.2067 20.068H16.8033L10.371 3.93188H6.68225Z"
+1 -1
View File
@@ -63,4 +63,4 @@
font-weight: 600;
color: var(--color-text);
}
}
}
+26
View File
@@ -0,0 +1,26 @@
/**
* Application-wide constants and configuration
*/
export const config = {
// GitHub
github: {
repoUrl: "https://github.com/sst/opencode",
starsFormatted: {
compact: "30K",
full: "30,000",
},
},
// Social links
social: {
twitter: "https://x.com/opencode",
discord: "https://discord.gg/opencode",
},
// Static stats (used on landing page)
stats: {
contributors: "250",
commits: "3,500",
monthlyUsers: "300,000",
},
} as const
+8 -3
View File
@@ -1,4 +1,5 @@
import { query } from "@solidjs/router"
import { config } from "~/config"
export const github = query(async () => {
"use server"
@@ -6,11 +7,15 @@ export const github = query(async () => {
"User-Agent":
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
}
const apiBaseUrl = config.github.repoUrl.replace(
"https://github.com/",
"https://api.github.com/repos/",
)
try {
const [meta, releases, contributors] = await Promise.all([
fetch("https://api.github.com/repos/sst/opencode", { headers }).then((res) => res.json()),
fetch("https://api.github.com/repos/sst/opencode/releases", { headers }).then((res) => res.json()),
fetch("https://api.github.com/repos/sst/opencode/contributors?per_page=1", { headers }),
fetch(apiBaseUrl, { headers }).then((res) => res.json()),
fetch(`${apiBaseUrl}/releases`, { headers }).then((res) => res.json()),
fetch(`${apiBaseUrl}/contributors?per_page=1`, { headers }),
])
const [release] = releases
const contributorCount = Number.parseInt(
@@ -2,6 +2,9 @@ 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")
const result = await AuthClient.authorize(
new URL("./callback", input.request.url).toString(),
"code",
)
return Response.redirect(result.url, 302)
}
@@ -299,7 +299,6 @@
transition: all 0.2s ease;
text-decoration: none;
&:hover:not(:disabled) {
background: var(--color-background-strong-hover);
}
@@ -385,23 +384,21 @@
0 1px 2px -1px rgba(19, 16, 16, 0.12);
@media (max-width: 40rem) {
box-shadow:
0 0 0 1px rgba(19, 16, 16, 0.16)
box-shadow: 0 0 0 1px rgba(19, 16, 16, 0.16);
}
&:hover {
background: var(--color-background);
}
&:active {
transform: scale(0.98);
box-shadow: 0 0 0 1px rgba(19, 16, 16, 0.08), 0 6px 8px -8px rgba(19, 16, 16, 0.50);
box-shadow:
0 0 0 1px rgba(19, 16, 16, 0.08),
0 6px 8px -8px rgba(19, 16, 16, 0.5);
}
}
@media (max-width: 60rem) {
padding: 2rem 1.5rem;
}
@@ -0,0 +1,5 @@
import { redirect } from "@solidjs/router"
export async function GET() {
return redirect("https://discord.gg/h5TNnkFVNy")
}
File diff suppressed because it is too large Load Diff
+138 -127
View File
@@ -13,146 +13,157 @@ export async function POST(input: APIEvent) {
input.request.headers.get("stripe-signature")!,
Resource.STRIPE_WEBHOOK_SECRET.value,
)
console.log(body.type, JSON.stringify(body, null, 2))
if (body.type === "customer.updated") {
// check default payment method changed
const prevInvoiceSettings = body.data.previous_attributes?.invoice_settings ?? {}
if (!("default_payment_method" in prevInvoiceSettings)) return
const customerID = body.data.object.id
const paymentMethodID = body.data.object.invoice_settings.default_payment_method as string
return (async () => {
if (body.type === "customer.updated") {
// check default payment method changed
const prevInvoiceSettings = body.data.previous_attributes?.invoice_settings ?? {}
if (!("default_payment_method" in prevInvoiceSettings)) return "ignored"
if (!customerID) throw new Error("Customer ID not found")
if (!paymentMethodID) throw new Error("Payment method ID not found")
const customerID = body.data.object.id
const paymentMethodID = body.data.object.invoice_settings.default_payment_method as string
const paymentMethod = await Billing.stripe().paymentMethods.retrieve(paymentMethodID)
await Database.use(async (tx) => {
await tx
.update(BillingTable)
.set({
paymentMethodID,
paymentMethodLast4: paymentMethod.card?.last4 ?? null,
paymentMethodType: paymentMethod.type,
})
.where(eq(BillingTable.customerID, customerID))
})
}
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 invoiceID = body.data.object.invoice as string
const amount = body.data.object.amount_total
if (!customerID) throw new Error("Customer ID not found")
if (!paymentMethodID) throw new Error("Payment method ID not found")
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")
if (!invoiceID) throw new Error("Invoice ID not found")
await Actor.provide("system", { workspaceID }, async () => {
const customer = await Billing.get()
if (customer?.customerID && customer.customerID !== customerID)
throw new Error("Customer ID mismatch")
// set customer metadata
if (!customer?.customerID) {
await Billing.stripe().customers.update(customerID, {
metadata: {
workspaceID,
},
})
}
// get payment method for the payment intent
const paymentIntent = await Billing.stripe().paymentIntents.retrieve(paymentID, {
expand: ["payment_method"],
})
const paymentMethod = paymentIntent.payment_method
if (!paymentMethod || typeof paymentMethod === "string")
throw new Error("Payment method not expanded")
const oldBillingInfo = await Database.use((tx) =>
tx
.select({
customerID: BillingTable.customerID,
})
.from(BillingTable)
.where(eq(BillingTable.workspaceID, workspaceID))
.then((rows) => rows[0]),
)
await Database.transaction(async (tx) => {
const paymentMethod = await Billing.stripe().paymentMethods.retrieve(paymentMethodID)
await Database.use(async (tx) => {
await tx
.update(BillingTable)
.set({
balance: sql`${BillingTable.balance} + ${centsToMicroCents(Billing.CHARGE_AMOUNT)}`,
customerID,
paymentMethodID: paymentMethod.id,
paymentMethodID,
paymentMethodLast4: paymentMethod.card?.last4 ?? null,
paymentMethodType: paymentMethod.type,
// enable reload if first time enabling billing
...(oldBillingInfo?.customerID
? {}
: {
reload: true,
reloadError: null,
timeReloadError: null,
}),
})
.where(eq(BillingTable.workspaceID, workspaceID))
await tx.insert(PaymentTable).values({
workspaceID,
id: Identifier.create("payment"),
amount: centsToMicroCents(Billing.CHARGE_AMOUNT),
paymentID,
invoiceID,
customerID,
.where(eq(BillingTable.customerID, customerID))
})
}
if (body.type === "checkout.session.completed") {
const workspaceID = body.data.object.metadata?.workspaceID
const amountInCents =
body.data.object.metadata?.amount && parseInt(body.data.object.metadata?.amount)
const customerID = body.data.object.customer as string
const paymentID = body.data.object.payment_intent as string
const invoiceID = body.data.object.invoice as string
if (!workspaceID) throw new Error("Workspace ID not found")
if (!customerID) throw new Error("Customer ID not found")
if (!amountInCents) throw new Error("Amount not found")
if (!paymentID) throw new Error("Payment ID not found")
if (!invoiceID) throw new Error("Invoice ID not found")
await Actor.provide("system", { workspaceID }, async () => {
const customer = await Billing.get()
if (customer?.customerID && customer.customerID !== customerID)
throw new Error("Customer ID mismatch")
// set customer metadata
if (!customer?.customerID) {
await Billing.stripe().customers.update(customerID, {
metadata: {
workspaceID,
},
})
}
// get payment method for the payment intent
const paymentIntent = await Billing.stripe().paymentIntents.retrieve(paymentID, {
expand: ["payment_method"],
})
const paymentMethod = paymentIntent.payment_method
if (!paymentMethod || typeof paymentMethod === "string")
throw new Error("Payment method not expanded")
await Database.transaction(async (tx) => {
await tx
.update(BillingTable)
.set({
balance: sql`${BillingTable.balance} + ${centsToMicroCents(amountInCents)}`,
customerID,
paymentMethodID: paymentMethod.id,
paymentMethodLast4: paymentMethod.card?.last4 ?? null,
paymentMethodType: paymentMethod.type,
// enable reload if first time enabling billing
...(customer?.customerID
? {}
: {
reload: true,
reloadError: null,
timeReloadError: null,
}),
})
.where(eq(BillingTable.workspaceID, workspaceID))
await tx.insert(PaymentTable).values({
workspaceID,
id: Identifier.create("payment"),
amount: centsToMicroCents(amountInCents),
paymentID,
invoiceID,
customerID,
})
})
})
}
if (body.type === "charge.refunded") {
const customerID = body.data.object.customer as string
const paymentIntentID = body.data.object.payment_intent as string
if (!customerID) throw new Error("Customer ID not found")
if (!paymentIntentID) throw new Error("Payment ID not found")
const workspaceID = await Database.use((tx) =>
tx
.select({
workspaceID: BillingTable.workspaceID,
})
.from(BillingTable)
.where(eq(BillingTable.customerID, customerID))
.then((rows) => rows[0]?.workspaceID),
)
if (!workspaceID) throw new Error("Workspace ID not found")
const amount = await Database.use((tx) =>
tx
.select({
amount: PaymentTable.amount,
})
.from(PaymentTable)
.where(
and(
eq(PaymentTable.paymentID, paymentIntentID),
eq(PaymentTable.workspaceID, workspaceID),
),
)
.then((rows) => rows[0]?.amount),
)
if (!amount) throw new Error("Payment not found")
await Database.transaction(async (tx) => {
await tx
.update(PaymentTable)
.set({
timeRefunded: new Date(body.created * 1000),
})
.where(
and(
eq(PaymentTable.paymentID, paymentIntentID),
eq(PaymentTable.workspaceID, workspaceID),
),
)
await tx
.update(BillingTable)
.set({
balance: sql`${BillingTable.balance} - ${amount}`,
})
.where(eq(BillingTable.workspaceID, workspaceID))
})
}
})()
.then((message) => {
return Response.json({ message: message ?? "done" }, { status: 200 })
})
}
if (body.type === "charge.refunded") {
const customerID = body.data.object.customer as string
const paymentIntentID = body.data.object.payment_intent as string
if (!customerID) throw new Error("Customer ID not found")
if (!paymentIntentID) throw new Error("Payment ID not found")
const workspaceID = await Database.use((tx) =>
tx
.select({
workspaceID: BillingTable.workspaceID,
})
.from(BillingTable)
.where(eq(BillingTable.customerID, customerID))
.then((rows) => rows[0]?.workspaceID),
)
if (!workspaceID) throw new Error("Workspace ID not found")
await Database.transaction(async (tx) => {
await tx
.update(PaymentTable)
.set({
timeRefunded: new Date(body.created * 1000),
})
.where(
and(
eq(PaymentTable.paymentID, paymentIntentID),
eq(PaymentTable.workspaceID, workspaceID),
),
)
await tx
.update(BillingTable)
.set({
balance: sql`${BillingTable.balance} - ${centsToMicroCents(Billing.CHARGE_AMOUNT)}`,
})
.where(eq(BillingTable.workspaceID, workspaceID))
.catch((error: any) => {
return Response.json({ message: error.message }, { status: 500 })
})
}
console.log("finished handling")
return Response.json("ok", { status: 200 })
}
+7 -5
View File
@@ -79,17 +79,19 @@ export default function Home() {
<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>
<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
<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
<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{" "}
@@ -121,7 +123,7 @@ export default function Home() {
<h3 data-component="title">homebrew</h3>
<button data-copy data-slot="button">
<span>
brew install <strong>sst/tap/opencode</strong>
brew install <strong>opencode</strong>
</span>
<CopyStatus />
</button>
@@ -14,4 +14,4 @@
color: var(--color-danger);
}
}
}
}
@@ -71,4 +71,4 @@
color: var(--color-text-muted);
}
}
}
}
@@ -85,7 +85,10 @@ export function WorkspacePicker() {
<Dropdown trigger={currentWorkspace()} align="left">
<For each={workspaces()}>
{(workspace) => (
<DropdownItem selected={workspace.id === params.id} onClick={() => handleSelectWorkspace(workspace.id)}>
<DropdownItem
selected={workspace.id === params.id}
onClick={() => handleSelectWorkspace(workspace.id)}
>
{workspace.name || workspace.slug}
</DropdownItem>
)}
@@ -95,7 +98,11 @@ export function WorkspacePicker() {
</button>
</Dropdown>
<Modal open={store.showForm} onClose={() => setStore("showForm", false)} title="Create New Workspace">
<Modal
open={store.showForm}
onClose={() => setStore("showForm", false)}
title="Create New Workspace"
>
<form data-slot="create-form" action={createWorkspace} method="post">
<div data-slot="create-input-group">
<input
@@ -104,4 +104,4 @@
}
}
}
}
}
@@ -71,6 +71,57 @@
flex: 1;
}
[data-slot="add-balance-form-container"] {
display: flex;
flex-direction: column;
gap: var(--space-2);
}
[data-slot="add-balance-form"] {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--space-3);
label {
font-size: var(--font-size-sm);
font-weight: 500;
color: var(--color-text-muted);
white-space: nowrap;
}
input[data-component="input"] {
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);
line-height: 1.5;
&:focus {
outline: none;
border-color: var(--color-accent);
box-shadow: 0 0 0 3px var(--color-accent-alpha);
}
&::placeholder {
color: var(--color-text-disabled);
}
}
[data-slot="form-actions"] {
display: flex;
gap: var(--space-2);
}
}
[data-slot="form-error"] {
color: var(--color-danger);
font-size: var(--font-size-sm);
line-height: 1.4;
}
[data-slot="credit-card"] {
padding: var(--space-2) var(--space-4);
background-color: var(--color-bg-surface);
@@ -131,4 +182,4 @@
padding: var(--space-4);
min-width: 150px;
}
}
}
@@ -1,24 +1,80 @@
import { action, useParams, useAction, createAsync, useSubmission } from "@solidjs/router"
import { createMemo, Match, Show, Switch } from "solid-js"
import { action, useParams, useAction, createAsync, useSubmission, json } from "@solidjs/router"
import { createMemo, Match, Show, Switch, createEffect } from "solid-js"
import { createStore } from "solid-js/store"
import { Billing } from "@opencode-ai/console-core/billing.js"
import { withActor } from "~/context/auth.withActor"
import { IconCreditCard, IconStripe } from "~/component/icon"
import styles from "./billing-section.module.css"
import { createCheckoutUrl, queryBillingInfo } from "../../common"
import { createCheckoutUrl, formatBalance, queryBillingInfo } from "../../common"
const createSessionUrl = action(async (workspaceID: string, returnUrl: string) => {
"use server"
return withActor(() => Billing.generateSessionUrl({ returnUrl }), workspaceID)
return json(
await withActor(
() =>
Billing.generateSessionUrl({ returnUrl })
.then((data) => ({ error: undefined, data }))
.catch((e) => ({
error: e.message as string,
data: undefined,
})),
workspaceID,
),
{ revalidate: queryBillingInfo.key },
)
}, "sessionUrl")
export function BillingSection() {
const params = useParams()
// ORIGINAL CODE - COMMENTED OUT FOR TESTING
const balanceInfo = createAsync(() => queryBillingInfo(params.id))
const createCheckoutUrlAction = useAction(createCheckoutUrl)
const createCheckoutUrlSubmission = useSubmission(createCheckoutUrl)
const createSessionUrlAction = useAction(createSessionUrl)
const createSessionUrlSubmission = useSubmission(createSessionUrl)
const billingInfo = createAsync(() => queryBillingInfo(params.id))
const checkoutAction = useAction(createCheckoutUrl)
const checkoutSubmission = useSubmission(createCheckoutUrl)
const sessionAction = useAction(createSessionUrl)
const sessionSubmission = useSubmission(createSessionUrl)
const [store, setStore] = createStore({
showAddBalanceForm: false,
addBalanceAmount: "",
checkoutRedirecting: false,
sessionRedirecting: false,
})
const balance = createMemo(() => formatBalance(billingInfo()?.balance ?? 0))
async function onClickCheckout() {
const amount = parseInt(store.addBalanceAmount)
const baseUrl = window.location.href
const checkout = await checkoutAction(params.id, amount, baseUrl, baseUrl)
if (checkout && checkout.data) {
setStore("checkoutRedirecting", true)
window.location.href = checkout.data
}
}
async function onClickSession() {
const baseUrl = window.location.href
const sessionUrl = await sessionAction(params.id, baseUrl)
if (sessionUrl && sessionUrl.data) {
setStore("sessionRedirecting", true)
window.location.href = sessionUrl.data
}
}
function showAddBalanceForm() {
while (true) {
checkoutSubmission.clear()
if (!checkoutSubmission.result) break
}
setStore({
showAddBalanceForm: true,
addBalanceAmount: billingInfo()!.reloadAmount.toString(),
})
}
function hideAddBalanceForm() {
setStore("showAddBalanceForm", false)
checkoutSubmission.clear()
}
// DUMMY DATA FOR TESTING - UNCOMMENT ONE OF THE SCENARIOS BELOW
@@ -72,10 +128,6 @@ export function BillingSection() {
// timeReloadError: null as Date | null
// })
const balanceAmount = createMemo(() => {
return ((balanceInfo()?.balance ?? 0) / 100000000).toFixed(2)
})
return (
<section class={styles.root}>
<div data-slot="section-title">
@@ -88,81 +140,110 @@ export function BillingSection() {
<div data-slot="section-content">
<div data-slot="balance-display">
<div data-slot="balance-amount">
<span data-slot="balance-value">
${balanceAmount() === "-0.00" ? "0.00" : balanceAmount()}
</span>
<span data-slot="balance-value">${balance()}</span>
<span data-slot="balance-label">Current Balance</span>
</div>
<Show when={balanceInfo()?.customerID}>
<Show when={billingInfo()?.customerID}>
<div data-slot="balance-right-section">
<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
}
}}
<Show
when={!store.showAddBalanceForm}
fallback={
<div data-slot="add-balance-form-container">
<div data-slot="add-balance-form">
<label>Add $</label>
<input
data-component="input"
type="number"
min={billingInfo()?.reloadAmountMin.toString()}
step="1"
value={store.addBalanceAmount}
onInput={(e) => {
setStore("addBalanceAmount", e.currentTarget.value)
checkoutSubmission.clear()
}}
placeholder="Enter amount"
/>
<div data-slot="form-actions">
<button
data-color="ghost"
type="button"
onClick={() => hideAddBalanceForm()}
>
Cancel
</button>
<button
data-color="primary"
type="button"
disabled={
!store.addBalanceAmount ||
checkoutSubmission.pending ||
store.checkoutRedirecting
}
onClick={onClickCheckout}
>
{checkoutSubmission.pending || store.checkoutRedirecting
? "Loading..."
: "Add"}
</button>
</div>
</div>
<Show
when={checkoutSubmission.result && (checkoutSubmission.result as any).error}
>
{(err: any) => <div data-slot="form-error">{err()}</div>}
</Show>
</div>
}
>
{createCheckoutUrlSubmission.pending ? "Loading..." : "Add Balance"}
</button>
<button data-color="primary" onClick={() => showAddBalanceForm()}>
Add Balance
</button>
</Show>
<div data-slot="credit-card">
<div data-slot="card-icon">
<Switch fallback={<IconCreditCard style={{ width: "24px", height: "24px" }} />}>
<Match when={balanceInfo()?.paymentMethodType === "link"}>
<Match when={billingInfo()?.paymentMethodType === "link"}>
<IconStripe style={{ width: "24px", height: "24px" }} />
</Match>
</Switch>
</div>
<div data-slot="card-details">
<Switch>
<Match when={balanceInfo()?.paymentMethodType === "card"}>
<Match when={billingInfo()?.paymentMethodType === "card"}>
<Show
when={balanceInfo()?.paymentMethodLast4}
when={billingInfo()?.paymentMethodLast4}
fallback={<span data-slot="number">----</span>}
>
<span data-slot="secret"></span>
<span data-slot="number">{balanceInfo()?.paymentMethodLast4}</span>
<span data-slot="number">{billingInfo()?.paymentMethodLast4}</span>
</Show>
</Match>
<Match when={balanceInfo()?.paymentMethodType === "link"}>
<Match when={billingInfo()?.paymentMethodType === "link"}>
<span data-slot="type">Linked to Stripe</span>
</Match>
</Switch>
</div>
<button
data-color="ghost"
disabled={createSessionUrlSubmission.pending}
onClick={async () => {
const baseUrl = window.location.href
const sessionUrl = await createSessionUrlAction(params.id, baseUrl)
if (sessionUrl) {
window.location.href = sessionUrl
}
}}
disabled={sessionSubmission.pending || store.sessionRedirecting}
onClick={onClickSession}
>
{createSessionUrlSubmission.pending ? "Loading..." : "Manage"}
{sessionSubmission.pending || store.sessionRedirecting ? "Loading..." : "Manage"}
</button>
</div>
</div>
</Show>
</div>
<Show when={!balanceInfo()?.customerID}>
<Show when={!billingInfo()?.customerID}>
<button
data-slot="enable-billing-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
}
}}
disabled={checkoutSubmission.pending || store.checkoutRedirecting}
onClick={onClickCheckout}
>
{createCheckoutUrlSubmission.pending ? "Loading..." : "Enable Billing"}
{checkoutSubmission.pending || store.checkoutRedirecting
? "Loading..."
: "Enable Billing"}
</button>
</Show>
</div>
@@ -93,4 +93,4 @@
margin: 0;
line-height: 1.4;
}
}
}
@@ -1,16 +1,10 @@
import { json, query, action, useParams, createAsync, useSubmission } from "@solidjs/router"
import { json, action, useParams, createAsync, useSubmission } from "@solidjs/router"
import { createEffect, Show } from "solid-js"
import { createStore } from "solid-js/store"
import { withActor } from "~/context/auth.withActor"
import { Billing } from "@opencode-ai/console-core/billing.js"
import styles from "./monthly-limit-section.module.css"
const getBillingInfo = query(async (workspaceID: string) => {
"use server"
return withActor(async () => {
return await Billing.get()
}, workspaceID)
}, "billing.get")
import { queryBillingInfo } from "../../common"
const setMonthlyLimit = action(async (form: FormData) => {
"use server"
@@ -28,7 +22,7 @@ const setMonthlyLimit = action(async (form: FormData) => {
.catch((e) => ({ error: e.message as string })),
workspaceID,
),
{ revalidate: getBillingInfo.key },
{ revalidate: queryBillingInfo.key },
)
}, "billing.setMonthlyLimit")
@@ -36,7 +30,7 @@ export function MonthlyLimitSection() {
const params = useParams()
const submission = useSubmission(setMonthlyLimit)
const [store, setStore] = createStore({ show: false })
const balanceInfo = createAsync(() => getBillingInfo(params.id))
const billingInfo = createAsync(() => queryBillingInfo(params.id))
let input: HTMLInputElement
@@ -68,13 +62,13 @@ export function MonthlyLimitSection() {
<section class={styles.root}>
<div data-slot="section-title">
<h2>Monthly Limit</h2>
<p>Set a monthly spending limit for your account.</p>
<p>Set a monthly usage limit for your account.</p>
</div>
<div data-slot="section-content">
<div data-slot="balance">
<div data-slot="amount">
{balanceInfo()?.monthlyLimit ? <span data-slot="currency">$</span> : null}
<span data-slot="value">{balanceInfo()?.monthlyLimit ?? "-"}</span>
{billingInfo()?.monthlyLimit ? <span data-slot="currency">$</span> : null}
<span data-slot="value">{billingInfo()?.monthlyLimit ?? "-"}</span>
</div>
<Show
when={!store.show}
@@ -106,15 +100,19 @@ export function MonthlyLimitSection() {
}
>
<button data-color="primary" onClick={() => show()}>
{balanceInfo()?.monthlyLimit ? "Edit Limit" : "Set Limit"}
{billingInfo()?.monthlyLimit ? "Edit Limit" : "Set Limit"}
</button>
</Show>
</div>
<Show when={balanceInfo()?.monthlyLimit} fallback={<p data-slot="usage-status">No spending limit set.</p>}>
<Show
when={billingInfo()?.monthlyLimit}
fallback={<p data-slot="usage-status">No usage limit set.</p>}
>
<p data-slot="usage-status">
Current usage for {new Date().toLocaleDateString("en-US", { month: "long", timeZone: "UTC" })} is $
Current usage for{" "}
{new Date().toLocaleDateString("en-US", { month: "long", timeZone: "UTC" })} is $
{(() => {
const dateLastUsed = balanceInfo()?.timeMonthlyUsageUpdated
const dateLastUsed = billingInfo()?.timeMonthlyUsageUpdated
if (!dateLastUsed) return "0"
const current = new Date().toLocaleDateString("en-US", {
@@ -128,7 +126,7 @@ export function MonthlyLimitSection() {
timeZone: "UTC",
})
if (current !== lastUsed) return "0"
return ((balanceInfo()?.monthlyUsage ?? 0) / 100000000).toFixed(2)
return ((billingInfo()?.monthlyUsage ?? 0) / 100000000).toFixed(2)
})()}
.
</p>
@@ -89,7 +89,10 @@ export function PaymentSection() {
<td data-slot="payment-receipt">
<button
onClick={async () => {
const receiptUrl = await downloadReceiptAction(params.id, payment.paymentID!)
const receiptUrl = await downloadReceiptAction(
params.id,
payment.paymentID!,
)
if (receiptUrl) {
window.open(receiptUrl, "_blank")
}
@@ -34,6 +34,206 @@
}
}
[data-slot="create-form"] {
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);
margin-top: var(--space-4);
[data-slot="form-field"] {
display: flex;
flex-direction: column;
gap: var(--space-2);
label {
display: flex;
flex-direction: column;
gap: var(--space-2);
}
[data-slot="field-label"] {
font-size: var(--font-size-sm);
font-weight: 500;
color: var(--color-text-muted);
}
[data-slot="toggle-container"] {
display: flex;
align-items: center;
}
input[data-component="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="input-row"] {
display: flex;
flex-direction: row;
gap: var(--space-3);
@media (max-width: 40rem) {
flex-direction: column;
gap: var(--space-2);
}
}
[data-slot="input-field"] {
display: flex;
flex-direction: column;
gap: var(--space-1);
flex: 1;
p {
line-height: 1.2;
margin: 0;
color: var(--color-text-muted);
font-size: var(--font-size-sm);
}
input[data-component="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);
line-height: 1.5;
min-width: 0;
&:focus {
outline: none;
border-color: var(--color-accent);
box-shadow: 0 0 0 3px var(--color-accent-alpha);
}
&::placeholder {
color: var(--color-text-disabled);
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
background-color: var(--color-bg-surface);
}
}
[data-slot="field-with-connector"] {
display: flex;
align-items: center;
gap: var(--space-2);
[data-slot="field-connector"] {
font-size: var(--font-size-sm);
color: var(--color-text-muted);
white-space: nowrap;
}
input[data-component="input"] {
flex: 1;
min-width: 80px;
}
}
}
[data-slot="form-actions"] {
display: flex;
gap: var(--space-2);
margin-top: var(--space-1);
}
[data-slot="form-error"] {
color: var(--color-danger);
font-size: var(--font-size-sm);
line-height: 1.4;
margin-top: calc(var(--space-1) * -1);
}
[data-slot="model-toggle-label"] {
position: relative;
display: inline-block;
width: 2.5rem;
height: 1.5rem;
cursor: pointer;
input {
opacity: 0;
width: 0;
height: 0;
}
span {
position: absolute;
inset: 0;
background-color: #ccc;
border: 1px solid #bbb;
border-radius: 1.5rem;
transition: all 0.3s ease;
cursor: pointer;
&::before {
content: "";
position: absolute;
top: 50%;
left: 0.125rem;
width: 1.25rem;
height: 1.25rem;
background-color: white;
border: 1px solid #ddd;
border-radius: 50%;
transform: translateY(-50%);
transition: all 0.3s ease;
}
}
input:checked + span {
background-color: #21ad0e;
border-color: #148605;
&::before {
transform: translateX(1rem) translateY(-50%);
}
}
&:hover span {
box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2);
}
input:checked:hover + span {
box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.3);
}
&:has(input:disabled) {
cursor: not-allowed;
}
input:disabled + span {
opacity: 0.5;
cursor: not-allowed;
}
}
}
[data-slot="reload-error"] {
display: flex;
align-items: center;
@@ -54,7 +254,8 @@
gap: var(--space-2);
margin: 0;
flex-shrink: 0;
padding: 0;
border: none;
}
}
}
@@ -1,17 +1,19 @@
import { json, query, action, useParams, createAsync, useSubmission } from "@solidjs/router"
import { Show } from "solid-js"
import { json, action, useParams, createAsync, useSubmission } from "@solidjs/router"
import { createEffect, Show } from "solid-js"
import { createStore } from "solid-js/store"
import { withActor } from "~/context/auth.withActor"
import { Billing } from "@opencode-ai/console-core/billing.js"
import { Database, eq } from "@opencode-ai/console-core/drizzle/index.js"
import { BillingTable } from "@opencode-ai/console-core/schema/billing.sql.js"
import styles from "./reload-section.module.css"
import { queryBillingInfo } from "../../common"
const reload = action(async (form: FormData) => {
"use server"
const workspaceID = form.get("workspaceID")?.toString()
if (!workspaceID) return { error: "Workspace ID is required" }
return json(await withActor(() => Billing.reload(), workspaceID), {
revalidate: getBillingInfo.key,
revalidate: queryBillingInfo.key,
})
}, "billing.reload")
@@ -20,12 +22,27 @@ const setReload = action(async (form: FormData) => {
const workspaceID = form.get("workspaceID")?.toString()
if (!workspaceID) return { error: "Workspace ID is required" }
const reloadValue = form.get("reload")?.toString() === "true"
const amountStr = form.get("reloadAmount")?.toString()
const triggerStr = form.get("reloadTrigger")?.toString()
const reloadAmount = amountStr && amountStr.trim() !== "" ? parseInt(amountStr) : null
const reloadTrigger = triggerStr && triggerStr.trim() !== "" ? parseInt(triggerStr) : null
if (reloadValue) {
if (reloadAmount === null || reloadAmount < Billing.RELOAD_AMOUNT_MIN)
return { error: `Reload amount must be at least $${Billing.RELOAD_AMOUNT_MIN}` }
if (reloadTrigger === null || reloadTrigger < Billing.RELOAD_TRIGGER_MIN)
return { error: `Balance trigger must be at least $${Billing.RELOAD_TRIGGER_MIN}` }
}
return json(
await Database.use((tx) =>
tx
.update(BillingTable)
.set({
reload: reloadValue,
...(reloadAmount !== null ? { reloadAmount } : {}),
...(reloadTrigger !== null ? { reloadTrigger } : {}),
...(reloadValue
? {
reloadError: null,
@@ -35,22 +52,47 @@ const setReload = action(async (form: FormData) => {
})
.where(eq(BillingTable.workspaceID, workspaceID)),
),
{ revalidate: getBillingInfo.key },
{ revalidate: queryBillingInfo.key },
)
}, "billing.setReload")
const getBillingInfo = query(async (workspaceID: string) => {
"use server"
return withActor(async () => {
return await Billing.get()
}, workspaceID)
}, "billing.get")
export function ReloadSection() {
const params = useParams()
const balanceInfo = createAsync(() => getBillingInfo(params.id))
const billingInfo = createAsync(() => queryBillingInfo(params.id))
const setReloadSubmission = useSubmission(setReload)
const reloadSubmission = useSubmission(reload)
const [store, setStore] = createStore({
show: false,
reload: false,
reloadAmount: "",
reloadTrigger: "",
})
createEffect(() => {
if (
!setReloadSubmission.pending &&
setReloadSubmission.result &&
!(setReloadSubmission.result as any).error
) {
setStore("show", false)
}
})
function show() {
while (true) {
setReloadSubmission.clear()
if (!setReloadSubmission.result) break
}
const info = billingInfo()!
setStore("show", true)
setStore("reload", info.reload ? true : true)
setStore("reloadAmount", info.reloadAmount.toString())
setStore("reloadTrigger", info.reloadTrigger.toString())
}
function hide() {
setStore("show", false)
}
return (
<section class={styles.root}>
@@ -58,43 +100,101 @@ export function ReloadSection() {
<h2>Auto Reload</h2>
<div data-slot="title-row">
<Show
when={balanceInfo()?.reload}
when={billingInfo()?.reload}
fallback={
<p>Auto reload is disabled. Enable to automatically reload when balance is low.</p>
<p>
Auto reload is <b>disabled</b>. Enable to automatically reload when balance is low.
</p>
}
>
<p>
We'll automatically reload <b>$20</b> (+$1.23 processing fee) when it reaches{" "}
<b>$5</b>.
Auto reload is <b>enabled</b>. We'll reload <b>${billingInfo()?.reloadAmount}</b>{" "}
(+$1.23 processing fee) when balance reaches <b>${billingInfo()?.reloadTrigger}</b>.
</p>
</Show>
<form action={setReload} method="post" data-slot="create-form">
<input type="hidden" name="workspaceID" value={params.id} />
<input type="hidden" name="reload" value={balanceInfo()?.reload ? "false" : "true"} />
<button data-color="primary" type="submit" disabled={setReloadSubmission.pending}>
<Show
when={balanceInfo()?.reload}
fallback={setReloadSubmission.pending ? "Enabling..." : "Enable"}
>
{setReloadSubmission.pending ? "Disabling..." : "Disable"}
</Show>
</button>
</form>
<button data-color="primary" type="button" onClick={() => show()}>
{billingInfo()?.reload ? "Edit" : "Enable"}
</button>
</div>
</div>
<div data-slot="section-content">
<Show when={balanceInfo()?.reload && balanceInfo()?.reloadError}>
<Show when={store.show}>
<form action={setReload} method="post" data-slot="create-form">
<div data-slot="form-field">
<label>
<span data-slot="field-label">Enable Auto Reload</span>
<div data-slot="toggle-container">
<label data-slot="model-toggle-label">
<input
type="checkbox"
name="reload"
value="true"
checked={store.reload}
onChange={(e) => setStore("reload", e.currentTarget.checked)}
/>
<span></span>
</label>
</div>
</label>
</div>
<div data-slot="input-row">
<div data-slot="input-field">
<p>Reload $</p>
<input
data-component="input"
name="reloadAmount"
type="number"
min={billingInfo()?.reloadAmountMin.toString()}
step="1"
value={store.reloadAmount}
onInput={(e) => setStore("reloadAmount", e.currentTarget.value)}
placeholder={billingInfo()?.reloadAmount.toString()}
disabled={!store.reload}
/>
</div>
<div data-slot="input-field">
<p>When balance reaches $</p>
<input
data-component="input"
name="reloadTrigger"
type="number"
min={billingInfo()?.reloadTriggerMin.toString()}
step="1"
value={store.reloadTrigger}
onInput={(e) => setStore("reloadTrigger", e.currentTarget.value)}
placeholder={billingInfo()?.reloadTrigger.toString()}
disabled={!store.reload}
/>
</div>
</div>
<Show when={setReloadSubmission.result && (setReloadSubmission.result as any).error}>
{(err: any) => <div data-slot="form-error">{err()}</div>}
</Show>
<input type="hidden" name="workspaceID" value={params.id} />
<div data-slot="form-actions">
<button type="button" data-color="ghost" onClick={() => hide()}>
Cancel
</button>
<button type="submit" data-color="primary" disabled={setReloadSubmission.pending}>
{setReloadSubmission.pending ? "Saving..." : "Save"}
</button>
</div>
</form>
</Show>
<Show when={billingInfo()?.reload && billingInfo()?.reloadError}>
<div data-slot="section-content">
<div data-slot="reload-error">
<p>
Reload failed at{" "}
{balanceInfo()?.timeReloadError!.toLocaleString("en-US", {
{billingInfo()?.timeReloadError!.toLocaleString("en-US", {
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
second: "2-digit",
})}
. Reason: {balanceInfo()?.reloadError?.replace(/\.$/, "")}. Please update your payment
. Reason: {billingInfo()?.reloadError?.replace(/\.$/, "")}. Please update your payment
method and try again.
</p>
<form action={reload} method="post" data-slot="create-form">
@@ -104,8 +204,8 @@ export function ReloadSection() {
</button>
</form>
</div>
</Show>
</div>
</div>
</Show>
</section>
)
}
@@ -1,22 +1,32 @@
import { Show, createMemo } from "solid-js"
import { createStore } from "solid-js/store"
import { createAsync, useParams, useAction, useSubmission } from "@solidjs/router"
import { NewUserSection } from "./new-user-section"
import { UsageSection } from "./usage-section"
import { ModelSection } from "./model-section"
import { ProviderSection } from "./provider-section"
import { IconLogo } from "~/component/icon"
import { createAsync, useParams, useAction, useSubmission } from "@solidjs/router"
import { querySessionInfo, queryBillingInfo, createCheckoutUrl } from "../common"
import { Show, createMemo } from "solid-js"
import { querySessionInfo, queryBillingInfo, createCheckoutUrl, formatBalance } from "../common"
export default function () {
const params = useParams()
const userInfo = createAsync(() => querySessionInfo(params.id))
const billingInfo = createAsync(() => queryBillingInfo(params.id))
const createCheckoutUrlAction = useAction(createCheckoutUrl)
const createCheckoutUrlSubmission = useSubmission(createCheckoutUrl)
const balanceAmount = createMemo(() => {
return ((billingInfo()?.balance ?? 0) / 100000000).toFixed(2)
const checkoutAction = useAction(createCheckoutUrl)
const checkoutSubmission = useSubmission(createCheckoutUrl)
const [store, setStore] = createStore({
checkoutRedirecting: false,
})
const balance = createMemo(() => formatBalance(billingInfo()?.balance ?? 0))
async function onClickCheckout() {
const baseUrl = window.location.href
const checkout = await checkoutAction(params.id, billingInfo()!.reloadAmount, baseUrl, baseUrl)
if (checkout && checkout.data) {
setStore("checkoutRedirecting", true)
window.location.href = checkout.data
}
}
return (
<div data-page="workspace-[id]">
@@ -38,21 +48,17 @@ export default function () {
<button
data-color="primary"
data-size="sm"
disabled={createCheckoutUrlSubmission.pending}
onClick={async () => {
const baseUrl = window.location.href
const checkoutUrl = await createCheckoutUrlAction(params.id, baseUrl, baseUrl)
if (checkoutUrl) {
window.location.href = checkoutUrl
}
}}
disabled={checkoutSubmission.pending || store.checkoutRedirecting}
onClick={onClickCheckout}
>
{createCheckoutUrlSubmission.pending ? "Loading..." : "Enable billing"}
{checkoutSubmission.pending || store.checkoutRedirecting
? "Loading..."
: "Enable billing"}
</button>
}
>
<span data-slot="balance">
Current balance <b>${balanceAmount() === "-0.00" ? "0.00" : balanceAmount()}</b>
Current balance <b>${balance()}</b>
</span>
</Show>
</span>
@@ -171,7 +171,6 @@
}
@media (max-width: 40rem) {
th,
td {
padding: var(--space-2) var(--space-3);
@@ -181,8 +180,7 @@
th {
&:nth-child(3)
/* Date */
{
/* Date */ {
display: none;
}
}
@@ -190,11 +188,10 @@
td {
&:nth-child(3)
/* Date */
{
/* Date */ {
display: none;
}
}
}
}
}
}
@@ -146,14 +146,20 @@ export function KeySection() {
title="Copy API key"
>
<span>{key.keyDisplay}</span>
<Show when={copied()} fallback={<IconCopy style={{ width: "14px", height: "14px" }} />}>
<Show
when={copied()}
fallback={<IconCopy style={{ width: "14px", height: "14px" }} />}
>
<IconCheck style={{ width: "14px", height: "14px" }} />
</Show>
</button>
</Show>
</td>
<td data-slot="key-user-email">{key.email}</td>
<td data-slot="key-last-used" title={key.timeUsed ? formatDateUTC(key.timeUsed) : undefined}>
<td
data-slot="key-last-used"
title={key.timeUsed ? formatDateUTC(key.timeUsed) : undefined}
>
{key.timeUsed ? formatDateForTable(key.timeUsed) : "-"}
</td>
<td data-slot="key-actions">
@@ -85,7 +85,12 @@ const updateMember = action(async (form: FormData) => {
)
}, "member.update")
function MemberRow(props: { member: any; workspaceID: string; actorID: string; actorRole: string }) {
function MemberRow(props: {
member: any
workspaceID: string
actorID: string
actorRole: string
}) {
const submission = useSubmission(updateMember)
const isCurrentUser = () => props.actorID === props.member.id
const isAdmin = () => props.actorRole === "admin"
@@ -69,4 +69,4 @@
}
}
}
}
}
@@ -31,6 +31,7 @@ const getModelsInfo = query(async (workspaceID: string) => {
return {
all: Object.entries(ZenData.list().models)
.filter(([id, _model]) => !["claude-3-5-haiku", "minimax-m2"].includes(id))
.filter(([id, _model]) => !id.startsWith("an-"))
.sort(([_idA, modelA], [_idB, modelB]) => modelA.name.localeCompare(modelB.name))
.map(([id, model]) => ({ id, name: model.name })),
disabled: await Model.listDisabled(),
@@ -140,4 +140,4 @@
}
}
}
}
}
@@ -43,15 +43,24 @@ export function NewUserSection() {
<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>
<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>
<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>
<p>
Use Zen with any coding agent, and continue using other providers with opencode
whenever you want.
</p>
</div>
</div>
@@ -128,7 +128,6 @@
}
@media (max-width: 40rem) {
th,
td {
padding: var(--space-2) var(--space-3);
@@ -136,4 +135,4 @@
}
}
}
}
}
@@ -22,7 +22,9 @@ const removeProvider = action(async (form: FormData) => {
if (!provider) return { error: "Provider is required" }
const workspaceID = form.get("workspaceID")?.toString()
if (!workspaceID) return { error: "Workspace ID is required" }
return json(await withActor(() => Provider.remove({ provider }), workspaceID), { revalidate: listProviders.key })
return json(await withActor(() => Provider.remove({ provider }), workspaceID), {
revalidate: listProviders.key,
})
}, "provider.remove")
const saveProvider = action(async (form: FormData) => {
@@ -53,7 +55,10 @@ const listProviders = query(async (workspaceID: string) => {
function ProviderRow(props: { provider: Provider }) {
const params = useParams()
const providers = createAsync(() => listProviders(params.id))
const saveSubmission = useSubmission(saveProvider, ([fd]) => fd.get("provider")?.toString() === props.provider.key)
const saveSubmission = useSubmission(
saveProvider,
([fd]) => fd.get("provider")?.toString() === props.provider.key,
)
const removeSubmission = useSubmission(
removeProvider,
([fd]) => fd.get("provider")?.toString() === props.provider.key,
@@ -89,9 +94,16 @@ function ProviderRow(props: { provider: Provider }) {
<td data-slot="provider-key">
<Show
when={store.editing}
fallback={<span>{providerData() ? maskCredentials(providerData()!.credentials) : "-"}</span>}
fallback={
<span>{providerData() ? maskCredentials(providerData()!.credentials) : "-"}</span>
}
>
<form id={`provider-form-${props.provider.key}`} action={saveProvider} method="post" data-slot="edit-form">
<form
id={`provider-form-${props.provider.key}`}
action={saveProvider}
method="post"
data-slot="edit-form"
>
<div data-slot="input-wrapper">
<input
ref={(r) => (input = r)}
@@ -31,7 +31,7 @@
margin: 0;
}
>button {
> button {
align-self: flex-start;
}
}
@@ -80,7 +80,7 @@
}
}
>button[type="reset"] {
> button[type="reset"] {
align-self: flex-start;
}
@@ -91,4 +91,4 @@
margin-top: calc(var(--space-1) * -1);
}
}
}
}
@@ -1,6 +1,6 @@
import { Resource } from "@opencode-ai/console-resource"
import { Actor } from "@opencode-ai/console-core/actor.js"
import { action, query } from "@solidjs/router"
import { action, json, query } from "@solidjs/router"
import { withActor } from "~/context/auth.withActor"
import { Billing } from "@opencode-ai/console-core/billing.js"
import { User } from "@opencode-ai/console-core/user.js"
@@ -34,6 +34,11 @@ export function formatDateUTC(date: Date) {
return date.toLocaleDateString("en-US", options)
}
export function formatBalance(amount: number) {
const balance = ((amount ?? 0) / 100000000).toFixed(2)
return balance === "-0.00" ? "0.00" : balance
}
export async function getLastSeenWorkspaceID() {
"use server"
return withActor(async () => {
@@ -71,14 +76,34 @@ export const querySessionInfo = query(async (workspaceID: string) => {
}, "session.get")
export const createCheckoutUrl = action(
async (workspaceID: string, successUrl: string, cancelUrl: string) => {
async (workspaceID: string, amount: number, successUrl: string, cancelUrl: string) => {
"use server"
return withActor(() => Billing.generateCheckoutUrl({ successUrl, cancelUrl }), workspaceID)
return json(
await withActor(
() =>
Billing.generateCheckoutUrl({ amount, successUrl, cancelUrl })
.then((data) => ({ error: undefined, data }))
.catch((e) => ({
error: e.message as string,
data: undefined,
})),
workspaceID,
),
)
},
"checkoutUrl",
)
export const queryBillingInfo = query(async (workspaceID: string) => {
"use server"
return withActor(() => Billing.get(), workspaceID)
return withActor(async () => {
const billing = await Billing.get()
return {
...billing,
reloadAmount: billing.reloadAmount ?? Billing.RELOAD_AMOUNT,
reloadAmountMin: Billing.RELOAD_AMOUNT_MIN,
reloadTrigger: billing.reloadTrigger ?? Billing.RELOAD_TRIGGER,
reloadTriggerMin: Billing.RELOAD_TRIGGER_MIN,
}
}, workspaceID)
}, "billing.get")
+96 -36
View File
@@ -28,7 +28,10 @@ export default function Home() {
createAsync(() => checkLoggedIn())
return (
<main data-page="zen">
<HttpHeader name="Cache-Control" value="public, max-age=1, s-maxage=3600, stale-while-revalidate=86400" />
<HttpHeader
name="Cache-Control"
value="public, max-age=1, s-maxage=3600, stale-while-revalidate=86400"
/>
<Title>OpenCode Zen | A curated set of reliable optimized models for coding agents</Title>
<Link rel="icon" type="image/svg+xml" href="/favicon-zen.svg" />
<Meta property="og:image" content="/social-share-zen.png" />
@@ -44,13 +47,19 @@ export default function Home() {
<img data-slot="zen logo dark" src={zenLogoDark} alt="zen logo dark" />
<strong>Reliable optimized models for coding agents</strong>
<p>
Zen gives you access to a curated set of AI models that OpenCode has tested and benchmarked specifically
for coding agents. No need to worry about inconsistent performance and quality, use validated models
that work.
Zen gives you access to a curated set of AI models that OpenCode has tested and
benchmarked specifically for coding agents. No need to worry about inconsistent
performance and quality, use validated models that work.
</p>
<div data-slot="model-logos">
<div>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<mask
id="mask0_79_128586"
style="mask-type:luminance"
@@ -71,8 +80,17 @@ export default function Home() {
</svg>
</div>
<div>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.7891 3.93164L20.2223 20.0677H23.7502L17.317 3.93164H13.7891Z" fill="currentColor" />
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M13.7891 3.93164L20.2223 20.0677H23.7502L17.317 3.93164H13.7891Z"
fill="currentColor"
/>
<path
d="M6.32538 13.6824L8.52662 8.01177L10.7279 13.6824H6.32538ZM6.68225 3.93164L0.25 20.0677H3.84652L5.16202 16.6791H11.8914L13.2067 20.0677H16.8033L10.371 3.93164H6.68225Z"
fill="currentColor"
@@ -80,7 +98,13 @@ export default function Home() {
</svg>
</div>
<div>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.16861 16.0529L17.2018 9.85156C17.5957 9.54755 18.1586 9.66612 18.3463 10.1384C19.3339 12.6288 18.8926 15.6217 16.9276 17.6766C14.9626 19.7314 12.2285 20.1821 9.72948 19.1557L6.9995 20.4775C10.9151 23.2763 15.6699 22.5841 18.6411 19.4749C20.9979 17.0103 21.7278 13.6508 21.0453 10.6214L21.0515 10.6278C20.0617 6.17736 21.2948 4.39847 23.8207 0.760904C23.8804 0.674655 23.9402 0.588405 24 0.5L20.6762 3.97585V3.96506L9.16658 16.0551"
fill="currentColor"
@@ -92,7 +116,13 @@ export default function Home() {
</svg>
</div>
<div>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
@@ -102,7 +132,13 @@ export default function Home() {
</svg>
</div>
<div>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.6241 11.346L20.3848 3.44816C20.5309 3.29931 20.4487 3 20.2601 3H16.0842C16.0388 3 15.9949 3.01897 15.9594 3.05541L7.59764 11.5629C7.46721 11.6944 7.27446 11.5771 7.27446 11.3666V3.25183C7.27446 3.11242 7.18515 3 7.07594 3H4.19843C4.08932 3 4 3.11242 4 3.25183V20.7482C4 20.8876 4.08932 21 4.19843 21H7.07594C7.18515 21 7.27446 20.8876 7.27446 20.7482V17.1834C7.27446 17.1073 7.30136 17.0344 7.34815 16.987L9.94075 14.3486C10.0031 14.2853 10.0895 14.2757 10.159 14.3232L17.0934 19.5573C18.2289 20.3412 19.4975 20.8226 20.786 20.9652C20.9008 20.9778 21 20.8606 21 20.7133V17.3559C21 17.2276 20.9249 17.1232 20.8243 17.1073C20.0659 16.9853 19.326 16.6845 18.6569 16.222L12.6538 11.764C12.5291 11.6785 12.5135 11.4584 12.6241 11.346Z"
fill="currentColor"
@@ -112,7 +148,13 @@ export default function Home() {
</div>
<a href="/auth">
<span>Get started with Zen </span>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.5 12L17 12M13 16.5L17.5 12L13 7.5"
stroke="currentColor"
@@ -124,14 +166,23 @@ export default function Home() {
</div>
<div data-slot="pricing-copy">
<p>
<strong>Add $20 Pay as you go balance</strong> <span>(+$1.23 card processing fee)</span>
<strong>Add $20 Pay as you go balance</strong>{" "}
<span>(+$1.23 card processing fee)</span>
</p>
<p>Use with any agent. Set monthly spend limits. Cancel any time.</p>
</div>
</section>
<section data-component="comparison">
<video src={compareVideo} autoplay playsinline loop muted preload="auto" poster={compareVideoPoster}>
<video
src={compareVideo}
autoplay
playsinline
loop
muted
preload="auto"
poster={compareVideoPoster}
>
Your browser does not support the video tag.
</video>
</section>
@@ -140,8 +191,8 @@ export default function Home() {
<div data-slot="section-title">
<h3>What problem is Zen solving?</h3>
<p>
There are so many models available, but only a few work well with coding agents. Most providers
configure them differently with varying results.
There are so many models available, but only a few work well with coding agents.
Most providers configure them differently with varying results.
</p>
</div>
<p>We're fixing this for everyone, not just OpenCode users.</p>
@@ -176,14 +227,15 @@ export default function Home() {
<li>
<span>[2]</span>
<div>
<strong>Use Zen with transparent pricing</strong> - <a href="/docs/zen/#pricing">pay per request</a>{" "}
with zero markups
<strong>Use Zen with transparent pricing</strong> -{" "}
<a href="/docs/zen/#pricing">pay per request</a> with zero markups
</div>
</li>
<li>
<span>[3]</span>
<div>
<strong>Auto-top up</strong> - when your balance reaches $5 well automatically add $20
<strong>Auto-top up</strong> - when your balance reaches $5 well automatically
add $20
</div>
</li>
</ul>
@@ -195,8 +247,9 @@ export default function Home() {
<div>
<span>[*]</span>
<p>
All Zen models are hosted in the US. Providers follow a zero-retention policy and do not use your data
for model training, with the <a href="/docs/zen/#privacy">following exceptions</a>.
All Zen models are hosted in the US. Providers follow a zero-retention policy and
do not use your data for model training, with the{" "}
<a href="/docs/zen/#privacy">following exceptions</a>.
</p>
</div>
</div>
@@ -251,7 +304,8 @@ export default function Home() {
<span>ex-Head of Design, Laravel</span>
</div>
<div data-slot="quote">
With <span>@OpenCode</span> Zen I know all the models are tested and perfect for coding agents.
With <span>@OpenCode</span> Zen I know all the models are tested and perfect for
coding agents.
</div>
</div>
</a>
@@ -275,38 +329,44 @@ export default function Home() {
<ul>
<li>
<Faq question="What is OpenCode Zen?">
Zen is a curated set of AI models tested and benchmarked for coding agents created by the team behind
OpenCode.
Zen is a curated set of AI models tested and benchmarked for coding agents created
by the team behind OpenCode.
</Faq>
</li>
<li>
<Faq question="What makes Zen more accurate?">
Zen only provides models that have been specifically tested and benchmarked for coding agents. You
wouldnt use a butter knife to cut steak, dont use poor models for coding.
Zen only provides models that have been specifically tested and benchmarked for
coding agents. You wouldnt use a butter knife to cut steak, dont use poor models
for coding.
</Faq>
</li>
<li>
<Faq question="Is Zen cheaper?">
Zen is not for profit. Zen passes through the costs from the model providers to you. The higher Zens
usage the more OpenCode can negotiate better rates and pass those to you.
Zen is not for profit. Zen passes through the costs from the model providers to
you. The higher Zens usage the more OpenCode can negotiate better rates and pass
those to you.
</Faq>
</li>
<li>
<Faq question="How much does Zen cost?">
Zen <a href="/docs/zen/#pricing">charges per request</a> with zero markups, so you pay exactly what
the model provider charges. Your total cost depends on usage, and you can set monthly spend limits in
your <a href="/auth">account</a>. To cover costs, OpenCode adds only a small payment processing fee of
$1.23 per $20 balance top-up.
Zen <a href="/docs/zen/#pricing">charges per request</a> with zero markups, so you
pay exactly what the model provider charges. Your total cost depends on usage, and
you can set monthly spend limits in your <a href="/auth">account</a>. To cover
costs, OpenCode adds only a small payment processing fee of $1.23 per $20 balance
top-up.
</Faq>
</li>
<li>
<Faq question="What about data and privacy?">
All Zen models are hosted in the US. Providers follow a zero-retention policy and do not use your data
for model training, with the <a href="/docs/zen/#privacy">following exceptions</a>.
All Zen models are hosted in the US. Providers follow a zero-retention policy and
do not use your data for model training, with the{" "}
<a href="/docs/zen/#privacy">following exceptions</a>.
</Faq>
</li>
<li>
<Faq question="Can I set spend limits?">Yes, you can set monthly spending limits in your account.</Faq>
<Faq question="Can I set spend limits?">
Yes, you can set monthly spending limits in your account.
</Faq>
</li>
<li>
<Faq question="Can I cancel?">
@@ -315,8 +375,8 @@ export default function Home() {
</li>
<li>
<Faq question="Can I use Zen with other coding agents?">
While Zen works great with OpenCode, you can use Zen with any agent. Follow the setup instructions in
your preferred coding agent.
While Zen works great with OpenCode, you can use Zen with any agent. Follow the
setup instructions in your preferred coding agent.
</Faq>
</li>
</ul>
@@ -1 +0,0 @@
export type Format = "anthropic" | "openai" | "oa-compat"
@@ -18,7 +18,6 @@ import {
createStreamPartConverter,
createResponseConverter,
} from "./provider/provider"
import { Format } from "./format"
import { anthropicHelper } from "./provider/anthropic"
import { openaiHelper } from "./provider/openai"
import { oaCompatHelper } from "./provider/openai-compatible"
@@ -29,7 +28,7 @@ type Model = ZenData["models"][string]
export async function handler(
input: APIEvent,
opts: {
format: Format
format: ZenData.Format
parseApiKey: (headers: Headers) => string | undefined
},
) {
@@ -248,12 +247,14 @@ export async function handler(
throw new ModelError(`Provider ${provider.id} not supported`)
}
const format = zenData.providers[provider.id].format
return {
...provider,
...zenData.providers[provider.id],
...(provider.id === "anthropic"
...(format === "anthropic"
? anthropicHelper
: provider.id === "openai"
: format === "openai"
? openaiHelper
: oaCompatHelper),
}
@@ -280,6 +281,7 @@ export async function handler(
monthlyLimit: BillingTable.monthlyLimit,
monthlyUsage: BillingTable.monthlyUsage,
timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated,
reloadTrigger: BillingTable.reloadTrigger,
},
user: {
id: UserTable.id,
@@ -531,7 +533,10 @@ export async function handler(
and(
eq(BillingTable.workspaceID, authInfo.workspaceID),
eq(BillingTable.reload, true),
lt(BillingTable.balance, centsToMicroCents(Billing.CHARGE_THRESHOLD)),
lt(
BillingTable.balance,
centsToMicroCents((authInfo.billing.reloadTrigger ?? Billing.RELOAD_TRIGGER) * 100),
),
or(
isNull(BillingTable.timeReloadLockedTill),
lt(BillingTable.timeReloadLockedTill, sql`now()`),
@@ -98,7 +98,10 @@ export function fromAnthropicRequest(body: any): CommonRequest {
typeof (src as any).media_type === "string" &&
typeof (src as any).data === "string"
)
return { type: "image_url", image_url: { url: `data:${(src as any).media_type};base64,${(src as any).data}` } }
return {
type: "image_url",
image_url: { url: `data:${(src as any).media_type};base64,${(src as any).data}` },
}
return undefined
}
@@ -120,12 +123,15 @@ export function fromAnthropicRequest(body: any): CommonRequest {
if ((p as any).type === "tool_result") {
const id = (p as any).tool_use_id
const content =
typeof (p as any).content === "string" ? (p as any).content : JSON.stringify((p as any).content)
typeof (p as any).content === "string"
? (p as any).content
: JSON.stringify((p as any).content)
msgs.push({ role: "tool", tool_call_id: id, content })
}
}
if (partsOut.length > 0) {
if (partsOut.length === 1 && partsOut[0].type === "text") msgs.push({ role: "user", content: partsOut[0].text })
if (partsOut.length === 1 && partsOut[0].type === "text")
msgs.push({ role: "user", content: partsOut[0].text })
else msgs.push({ role: "user", content: partsOut })
}
continue
@@ -137,7 +143,8 @@ export function fromAnthropicRequest(body: any): CommonRequest {
const tcs: any[] = []
for (const p of partsIn) {
if (!p || !(p as any).type) continue
if ((p as any).type === "text" && typeof (p as any).text === "string") texts.push((p as any).text)
if ((p as any).type === "text" && typeof (p as any).text === "string")
texts.push((p as any).text)
if ((p as any).type === "tool_use") {
const name = (p as any).name
const id = (p as any).id
@@ -165,7 +172,11 @@ export function fromAnthropicRequest(body: any): CommonRequest {
.filter((t: any) => t && typeof t === "object" && "input_schema" in t)
.map((t: any) => ({
type: "function",
function: { name: (t as any).name, description: (t as any).description, parameters: (t as any).input_schema },
function: {
name: (t as any).name,
description: (t as any).description,
parameters: (t as any).input_schema,
},
}))
: undefined
@@ -203,7 +214,9 @@ export function fromAnthropicRequest(body: any): CommonRequest {
export function toAnthropicRequest(body: CommonRequest) {
if (!body || typeof body !== "object") return body
const sysIn = Array.isArray(body.messages) ? body.messages.filter((m: any) => m && m.role === "system") : []
const sysIn = Array.isArray(body.messages)
? body.messages.filter((m: any) => m && m.role === "system")
: []
let ccCount = 0
const cc = () => {
ccCount++
@@ -354,7 +367,9 @@ export function fromAnthropicResponse(resp: any): CommonResponse {
const idIn = (resp as any).id
const id =
typeof idIn === "string" ? idIn.replace(/^msg_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}`
typeof idIn === "string"
? idIn.replace(/^msg_/, "chatcmpl_")
: `chatcmpl_${Math.random().toString(36).slice(2)}`
const model = (resp as any).model
const blocks: any[] = Array.isArray((resp as any).content) ? (resp as any).content : []
@@ -397,7 +412,9 @@ export function fromAnthropicResponse(resp: any): CommonResponse {
const ct = typeof (u as any).output_tokens === "number" ? (u as any).output_tokens : undefined
const total = pt != null && ct != null ? pt + ct : undefined
const cached =
typeof (u as any).cache_read_input_tokens === "number" ? (u as any).cache_read_input_tokens : undefined
typeof (u as any).cache_read_input_tokens === "number"
? (u as any).cache_read_input_tokens
: undefined
const details = cached != null ? { cached_tokens: cached } : undefined
return {
prompt_tokens: pt,
@@ -452,7 +469,12 @@ export function toAnthropicResponse(resp: CommonResponse) {
} catch {
input = (tc as any).function.arguments
}
content.push({ type: "tool_use", id: (tc as any).id, name: (tc as any).function.name, input })
content.push({
type: "tool_use",
id: (tc as any).id,
name: (tc as any).function.name,
input,
})
}
}
}
@@ -511,13 +533,22 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string {
if (json.type === "content_block_start") {
const cb = json.content_block
if (cb?.type === "text") {
out.choices.push({ index: json.index ?? 0, delta: { role: "assistant", content: "" }, finish_reason: null })
out.choices.push({
index: json.index ?? 0,
delta: { role: "assistant", content: "" },
finish_reason: null,
})
} else if (cb?.type === "tool_use") {
out.choices.push({
index: json.index ?? 0,
delta: {
tool_calls: [
{ index: json.index ?? 0, id: cb.id, type: "function", function: { name: cb.name, arguments: "" } },
{
index: json.index ?? 0,
id: cb.id,
type: "function",
function: { name: cb.name, arguments: "" },
},
],
},
finish_reason: null,
@@ -532,7 +563,9 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string {
} else if (d?.type === "input_json_delta") {
out.choices.push({
index: json.index ?? 0,
delta: { tool_calls: [{ index: json.index ?? 0, function: { arguments: d.partial_json } }] },
delta: {
tool_calls: [{ index: json.index ?? 0, function: { arguments: d.partial_json } }],
},
finish_reason: null,
})
}
@@ -558,7 +591,9 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string {
prompt_tokens: u.input_tokens,
completion_tokens: u.output_tokens,
total_tokens: (u.input_tokens || 0) + (u.output_tokens || 0),
...(u.cache_read_input_tokens ? { prompt_tokens_details: { cached_tokens: u.cache_read_input_tokens } } : {}),
...(u.cache_read_input_tokens
? { prompt_tokens_details: { cached_tokens: u.cache_read_input_tokens } }
: {}),
}
}
@@ -57,7 +57,8 @@ export const oaCompatHelper = {
const inputTokens = usage.prompt_tokens ?? 0
const outputTokens = usage.completion_tokens ?? 0
const reasoningTokens = usage.completion_tokens_details?.reasoning_tokens ?? undefined
const cacheReadTokens = usage.cached_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? undefined
const cacheReadTokens =
usage.cached_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? undefined
return {
inputTokens: inputTokens - (cacheReadTokens ?? 0),
outputTokens,
@@ -79,7 +80,8 @@ export function fromOaCompatibleRequest(body: any): CommonRequest {
if (!m || !m.role) continue
if (m.role === "system") {
if (typeof m.content === "string" && m.content.length > 0) msgsOut.push({ role: "system", content: m.content })
if (typeof m.content === "string" && m.content.length > 0)
msgsOut.push({ role: "system", content: m.content })
continue
}
@@ -90,10 +92,12 @@ export function fromOaCompatibleRequest(body: any): CommonRequest {
const parts: any[] = []
for (const p of m.content) {
if (!p || !p.type) continue
if (p.type === "text" && typeof p.text === "string") parts.push({ type: "text", text: p.text })
if (p.type === "text" && typeof p.text === "string")
parts.push({ type: "text", text: p.text })
if (p.type === "image_url") parts.push({ type: "image_url", image_url: p.image_url })
}
if (parts.length === 1 && parts[0].type === "text") msgsOut.push({ role: "user", content: parts[0].text })
if (parts.length === 1 && parts[0].type === "text")
msgsOut.push({ role: "user", content: parts[0].text })
else if (parts.length > 0) msgsOut.push({ role: "user", content: parts })
}
continue
@@ -137,7 +141,8 @@ export function toOaCompatibleRequest(body: CommonRequest) {
if (p.type === "image_url" && p.image_url) return { type: "image_url", image_url: p.image_url }
const s = (p as any).source
if (!s || typeof s !== "object") return undefined
if (s.type === "url" && typeof s.url === "string") return { type: "image_url", image_url: { url: s.url } }
if (s.type === "url" && typeof s.url === "string")
return { type: "image_url", image_url: { url: s.url } }
if (s.type === "base64" && typeof s.media_type === "string" && typeof s.data === "string")
return { type: "image_url", image_url: { url: `data:${s.media_type};base64,${s.data}` } }
return undefined
@@ -147,7 +152,8 @@ export function toOaCompatibleRequest(body: CommonRequest) {
if (!m || !m.role) continue
if (m.role === "system") {
if (typeof m.content === "string" && m.content.length > 0) msgsOut.push({ role: "system", content: m.content })
if (typeof m.content === "string" && m.content.length > 0)
msgsOut.push({ role: "system", content: m.content })
continue
}
@@ -160,11 +166,13 @@ export function toOaCompatibleRequest(body: CommonRequest) {
const parts: any[] = []
for (const p of m.content) {
if (!p || !p.type) continue
if (p.type === "text" && typeof p.text === "string") parts.push({ type: "text", text: p.text })
if (p.type === "text" && typeof p.text === "string")
parts.push({ type: "text", text: p.text })
const ip = toImg(p)
if (ip) parts.push(ip)
}
if (parts.length === 1 && parts[0].type === "text") msgsOut.push({ role: "user", content: parts[0].text })
if (parts.length === 1 && parts[0].type === "text")
msgsOut.push({ role: "user", content: parts[0].text })
else if (parts.length > 0) msgsOut.push({ role: "user", content: parts })
}
continue
@@ -317,7 +325,9 @@ export function toOaCompatibleResponse(resp: CommonResponse) {
const idIn = (resp as any).id
const id =
typeof idIn === "string" ? idIn.replace(/^msg_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}`
typeof idIn === "string"
? idIn.replace(/^msg_/, "chatcmpl_")
: `chatcmpl_${Math.random().toString(36).slice(2)}`
const model = (resp as any).model
const blocks: any[] = Array.isArray((resp as any).content) ? (resp as any).content : []
@@ -359,7 +369,8 @@ export function toOaCompatibleResponse(resp: CommonResponse) {
const pt = typeof u.input_tokens === "number" ? u.input_tokens : undefined
const ct = typeof u.output_tokens === "number" ? u.output_tokens : undefined
const total = pt != null && ct != null ? pt + ct : undefined
const cached = typeof u.cache_read_input_tokens === "number" ? u.cache_read_input_tokens : undefined
const cached =
typeof u.cache_read_input_tokens === "number" ? u.cache_read_input_tokens : undefined
const details = cached != null ? { cached_tokens: cached } : undefined
return {
prompt_tokens: pt,
@@ -532,7 +543,9 @@ export function toOaCompatibleChunk(chunk: CommonChunk): string {
total_tokens: chunk.usage.total_tokens,
...(chunk.usage.prompt_tokens_details?.cached_tokens
? {
prompt_tokens_details: { cached_tokens: chunk.usage.prompt_tokens_details.cached_tokens },
prompt_tokens_details: {
cached_tokens: chunk.usage.prompt_tokens_details.cached_tokens,
},
}
: {}),
}
@@ -77,13 +77,20 @@ export function fromOpenaiRequest(body: any): CommonRequest {
typeof (s as any).media_type === "string" &&
typeof (s as any).data === "string"
)
return { type: "image_url", image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` } }
return {
type: "image_url",
image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` },
}
return undefined
}
const msgs: any[] = []
const inMsgs = Array.isArray(body.input) ? body.input : Array.isArray(body.messages) ? body.messages : []
const inMsgs = Array.isArray(body.input)
? body.input
: Array.isArray(body.messages)
? body.messages
: []
for (const m of inMsgs) {
if (!m) continue
@@ -96,7 +103,9 @@ export function fromOpenaiRequest(body: any): CommonRequest {
const args = typeof a === "string" ? a : JSON.stringify(a ?? {})
msgs.push({
role: "assistant",
tool_calls: [{ id: (m as any).id, type: "function", function: { name, arguments: args } }],
tool_calls: [
{ id: (m as any).id, type: "function", function: { name, arguments: args } },
],
})
}
if ((m as any).type === "function_call_output") {
@@ -113,7 +122,8 @@ export function fromOpenaiRequest(body: any): CommonRequest {
if (typeof c === "string" && c.length > 0) msgs.push({ role: "system", content: c })
if (Array.isArray(c)) {
const t = c.find((p: any) => p && typeof p.text === "string")
if (t && typeof t.text === "string" && t.text.length > 0) msgs.push({ role: "system", content: t.text })
if (t && typeof t.text === "string" && t.text.length > 0)
msgs.push({ role: "system", content: t.text })
}
continue
}
@@ -126,18 +136,24 @@ export function fromOpenaiRequest(body: any): CommonRequest {
const parts: any[] = []
for (const p of c) {
if (!p || !(p as any).type) continue
if (((p as any).type === "text" || (p as any).type === "input_text") && typeof (p as any).text === "string")
if (
((p as any).type === "text" || (p as any).type === "input_text") &&
typeof (p as any).text === "string"
)
parts.push({ type: "text", text: (p as any).text })
const ip = toImg(p)
if (ip) parts.push(ip)
if ((p as any).type === "tool_result") {
const id = (p as any).tool_call_id
const content =
typeof (p as any).content === "string" ? (p as any).content : JSON.stringify((p as any).content)
typeof (p as any).content === "string"
? (p as any).content
: JSON.stringify((p as any).content)
msgs.push({ role: "tool", tool_call_id: id, content })
}
}
if (parts.length === 1 && parts[0].type === "text") msgs.push({ role: "user", content: parts[0].text })
if (parts.length === 1 && parts[0].type === "text")
msgs.push({ role: "user", content: parts[0].text })
else if (parts.length > 0) msgs.push({ role: "user", content: parts })
}
continue
@@ -153,7 +169,11 @@ export function fromOpenaiRequest(body: any): CommonRequest {
}
if ((m as any).role === "tool") {
msgs.push({ role: "tool", tool_call_id: (m as any).tool_call_id, content: (m as any).content })
msgs.push({
role: "tool",
tool_call_id: (m as any).tool_call_id,
content: (m as any).content,
})
continue
}
}
@@ -210,7 +230,10 @@ export function toOpenaiRequest(body: CommonRequest) {
typeof (s as any).media_type === "string" &&
typeof (s as any).data === "string"
)
return { type: "input_image", image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` } }
return {
type: "input_image",
image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` },
}
return undefined
}
@@ -257,7 +280,10 @@ export function toOpenaiRequest(body: CommonRequest) {
}
if ((m as any).role === "tool") {
const out = typeof (m as any).content === "string" ? (m as any).content : JSON.stringify((m as any).content)
const out =
typeof (m as any).content === "string"
? (m as any).content
: JSON.stringify((m as any).content)
input.push({ type: "function_call_output", call_id: (m as any).tool_call_id, output: out })
continue
}
@@ -325,7 +351,9 @@ export function fromOpenaiResponse(resp: any): CommonResponse {
const idIn = (r as any).id
const id =
typeof idIn === "string" ? idIn.replace(/^resp_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}`
typeof idIn === "string"
? idIn.replace(/^resp_/, "chatcmpl_")
: `chatcmpl_${Math.random().toString(36).slice(2)}`
const model = (r as any).model ?? (resp as any).model
const out = Array.isArray((r as any).output) ? (r as any).output : []
@@ -452,7 +480,9 @@ export function toOpenaiResponse(resp: CommonResponse) {
})()
return {
id: (resp as any).id?.replace(/^chatcmpl_/, "resp_") ?? `resp_${Math.random().toString(36).slice(2)}`,
id:
(resp as any).id?.replace(/^chatcmpl_/, "resp_") ??
`resp_${Math.random().toString(36).slice(2)}`,
object: "response",
model: (resp as any).model,
output: outputItems,
@@ -498,7 +528,9 @@ export function fromOpenaiChunk(chunk: string): CommonChunk | string {
if (typeof name === "string" && name.length > 0) {
out.choices.push({
index: 0,
delta: { tool_calls: [{ index: 0, id, type: "function", function: { name, arguments: "" } }] },
delta: {
tool_calls: [{ index: 0, id, type: "function", function: { name, arguments: "" } }],
},
finish_reason: null,
})
}
@@ -555,7 +587,12 @@ export function toOpenaiChunk(chunk: CommonChunk): string {
const model = chunk.model
if (d.content) {
const data = { id, type: "response.output_text.delta", delta: d.content, response: { id, model } }
const data = {
id,
type: "response.output_text.delta",
delta: d.content,
response: { id, model },
}
return `event: response.output_text.delta\ndata: ${JSON.stringify(data)}`
}
@@ -565,7 +602,13 @@ export function toOpenaiChunk(chunk: CommonChunk): string {
const data = {
type: "response.output_item.added",
output_index: 0,
item: { id: tc.id, type: "function_call", name: tc.function.name, call_id: tc.id, arguments: "" },
item: {
id: tc.id,
type: "function_call",
name: tc.function.name,
call_id: tc.id,
arguments: "",
},
}
return `event: response.output_item.added\ndata: ${JSON.stringify(data)}`
}
@@ -593,7 +636,11 @@ export function toOpenaiChunk(chunk: CommonChunk): string {
}
: undefined
const data: any = { id, type: "response.completed", response: { id, model, ...(usage ? { usage } : {}) } }
const data: any = {
id,
type: "response.completed",
response: { id, model, ...(usage ? { usage } : {}) },
}
return `event: response.completed\ndata: ${JSON.stringify(data)}`
}
@@ -1,5 +1,4 @@
import { Format } from "../format"
import { ZenData } from "@opencode-ai/console-core/model.js"
import {
fromAnthropicChunk,
fromAnthropicRequest,
@@ -26,7 +25,7 @@ import {
} from "./openai-compatible"
export type ProviderHelper = {
format: Format
format: ZenData.Format
modifyUrl: (providerApi: string) => string
modifyHeaders: (headers: Headers, body: Record<string, any>, apiKey: string) => void
modifyBody: (body: Record<string, any>) => Record<string, any>
@@ -158,7 +157,7 @@ export interface CommonChunk {
}
}
export function createBodyConverter(from: Format, to: Format) {
export function createBodyConverter(from: ZenData.Format, to: ZenData.Format) {
return (body: any): any => {
if (from === to) return body
@@ -173,7 +172,7 @@ export function createBodyConverter(from: Format, to: Format) {
}
}
export function createStreamPartConverter(from: Format, to: Format) {
export function createStreamPartConverter(from: ZenData.Format, to: ZenData.Format) {
return (part: any): any => {
if (from === to) return part
@@ -191,7 +190,7 @@ export function createStreamPartConverter(from: Format, to: Format) {
}
}
export function createResponseConverter(from: Format, to: Format) {
export function createResponseConverter(from: ZenData.Format, to: ZenData.Format) {
return (response: any): any => {
if (from === to) return response
@@ -15,6 +15,7 @@ body {
--font-size-9xl: 8rem;
--font-mono:
"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace;
--font-sans: var(--font-mono);
}
+1 -1
View File
@@ -6,4 +6,4 @@
/// <reference path="../../../sst-env.d.ts" />
import "sst"
export {}
export {}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": [
"workspace_id",
"name"
],
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -599,10 +578,7 @@
"indexes": {
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
@@ -610,10 +586,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -670,9 +643,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -680,9 +651,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -699,4 +668,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": [
"workspace_id",
"name"
],
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -599,10 +578,7 @@
"indexes": {
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
@@ -610,10 +586,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -670,9 +643,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -680,9 +651,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -699,4 +668,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": [
"workspace_id",
"name"
],
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -592,10 +571,7 @@
"indexes": {
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
@@ -603,10 +579,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -663,9 +636,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -673,9 +644,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -692,4 +661,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": [
"workspace_id",
"name"
],
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -599,10 +578,7 @@
"indexes": {
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
@@ -610,10 +586,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -670,9 +643,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -680,9 +651,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -699,4 +668,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": [
"workspace_id",
"name"
],
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -613,18 +592,12 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
}
},
@@ -632,10 +605,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -692,9 +662,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -702,9 +670,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -721,4 +687,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": [
"workspace_id",
"name"
],
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -613,32 +592,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -646,10 +615,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -706,9 +672,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -716,9 +680,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -735,4 +697,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,17 +473,12 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": [
"workspace_id",
"name"
],
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -504,10 +486,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -599,32 +578,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -632,10 +601,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -692,9 +658,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -702,9 +666,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -721,4 +683,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -493,17 +480,12 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
},
"name": {
"name": "name",
"columns": [
"workspace_id",
"name"
],
"columns": ["workspace_id", "name"],
"isUnique": true
}
},
@@ -511,10 +493,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -606,32 +585,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -639,10 +608,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -699,9 +665,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -709,9 +673,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -728,4 +690,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -493,9 +480,7 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
}
},
@@ -503,10 +488,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -598,32 +580,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -631,10 +603,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -691,9 +660,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -701,9 +668,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -720,4 +685,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -479,9 +466,7 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
}
},
@@ -489,10 +474,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -584,32 +566,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -617,10 +589,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -677,9 +646,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -687,9 +654,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -706,4 +671,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -479,9 +466,7 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
}
},
@@ -489,10 +474,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -584,32 +566,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -617,10 +589,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -677,9 +646,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -687,9 +654,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -706,4 +671,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -479,9 +466,7 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
}
},
@@ -489,10 +474,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -605,32 +587,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -638,10 +610,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -698,9 +667,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -708,9 +675,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -727,4 +692,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -479,9 +466,7 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
}
},
@@ -489,10 +474,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -549,10 +531,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
"columns": [
"workspace_id",
"model"
],
"columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -560,10 +539,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -676,32 +652,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -709,10 +675,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -769,9 +732,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -779,9 +740,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -798,4 +757,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -398,10 +388,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -479,9 +466,7 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
}
},
@@ -489,10 +474,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -549,10 +531,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
"columns": [
"workspace_id",
"model"
],
"columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -560,10 +539,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -627,10 +603,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
"columns": [
"workspace_id",
"provider"
],
"columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -638,10 +611,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -754,32 +724,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -787,10 +747,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -847,9 +804,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -857,9 +812,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -876,4 +829,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -180,9 +178,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -190,10 +186,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -280,10 +273,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -405,10 +395,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -486,9 +473,7 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
}
},
@@ -496,10 +481,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -556,10 +538,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
"columns": [
"workspace_id",
"model"
],
"columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -567,10 +546,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -634,10 +610,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
"columns": [
"workspace_id",
"provider"
],
"columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -645,10 +618,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -761,32 +731,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -794,10 +754,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -854,9 +811,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -864,9 +819,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -883,4 +836,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -187,9 +185,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -197,10 +193,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -287,10 +280,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -412,10 +402,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -493,9 +480,7 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
}
},
@@ -503,10 +488,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -563,10 +545,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
"columns": [
"workspace_id",
"model"
],
"columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -574,10 +553,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -641,10 +617,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
"columns": [
"workspace_id",
"provider"
],
"columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -652,10 +625,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -768,32 +738,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -801,10 +761,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -861,9 +818,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -871,9 +826,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -890,4 +843,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -48,9 +48,7 @@
"indexes": {
"email": {
"name": "email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": true
}
},
@@ -117,10 +115,7 @@
"indexes": {
"provider": {
"name": "provider",
"columns": [
"provider",
"subject"
],
"columns": ["provider", "subject"],
"isUnique": true
}
},
@@ -257,9 +252,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -267,10 +260,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -357,10 +347,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -482,10 +469,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -563,9 +547,7 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
}
},
@@ -573,10 +555,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -633,10 +612,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
"columns": [
"workspace_id",
"model"
],
"columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -644,10 +620,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -711,10 +684,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
"columns": [
"workspace_id",
"provider"
],
"columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -722,10 +692,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -838,32 +805,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -871,10 +828,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -931,9 +885,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -941,9 +893,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -960,4 +910,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -102,17 +102,12 @@
"indexes": {
"provider": {
"name": "provider",
"columns": [
"provider",
"subject"
],
"columns": ["provider", "subject"],
"isUnique": true
},
"account_id": {
"name": "account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
}
},
@@ -249,9 +244,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -259,10 +252,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -349,10 +339,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -474,10 +461,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -555,9 +539,7 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
}
},
@@ -565,10 +547,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -625,10 +604,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
"columns": [
"workspace_id",
"model"
],
"columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -636,10 +612,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -703,10 +676,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
"columns": [
"workspace_id",
"provider"
],
"columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -714,10 +684,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -830,32 +797,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -863,10 +820,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -923,9 +877,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -933,9 +885,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -952,4 +902,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -43,9 +43,7 @@
"compositePrimaryKeys": {
"account_id_pk": {
"name": "account_id_pk",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -109,17 +107,12 @@
"indexes": {
"provider": {
"name": "provider",
"columns": [
"provider",
"subject"
],
"columns": ["provider", "subject"],
"isUnique": true
},
"account_id": {
"name": "account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
}
},
@@ -127,9 +120,7 @@
"compositePrimaryKeys": {
"auth_id_pk": {
"name": "auth_id_pk",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -263,9 +254,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -273,10 +262,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -363,10 +349,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -488,10 +471,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -569,9 +549,7 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
}
},
@@ -579,10 +557,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -639,10 +614,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
"columns": [
"workspace_id",
"model"
],
"columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -650,10 +622,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -717,10 +686,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
"columns": [
"workspace_id",
"provider"
],
"columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -728,10 +694,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -844,32 +807,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -877,10 +830,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -937,9 +887,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -947,9 +895,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -966,4 +912,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -43,9 +43,7 @@
"compositePrimaryKeys": {
"account_id_pk": {
"name": "account_id_pk",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -109,17 +107,12 @@
"indexes": {
"provider": {
"name": "provider",
"columns": [
"provider",
"subject"
],
"columns": ["provider", "subject"],
"isUnique": true
},
"account_id": {
"name": "account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
}
},
@@ -127,9 +120,7 @@
"compositePrimaryKeys": {
"auth_id_pk": {
"name": "auth_id_pk",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -277,9 +268,7 @@
"indexes": {
"global_customer_id": {
"name": "global_customer_id",
"columns": [
"customer_id"
],
"columns": ["customer_id"],
"isUnique": true
}
},
@@ -287,10 +276,7 @@
"compositePrimaryKeys": {
"billing_workspace_id_id_pk": {
"name": "billing_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -377,10 +363,7 @@
"compositePrimaryKeys": {
"payment_workspace_id_id_pk": {
"name": "payment_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -502,10 +485,7 @@
"compositePrimaryKeys": {
"usage_workspace_id_id_pk": {
"name": "usage_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -583,9 +563,7 @@
"indexes": {
"global_key": {
"name": "global_key",
"columns": [
"key"
],
"columns": ["key"],
"isUnique": true
}
},
@@ -593,10 +571,7 @@
"compositePrimaryKeys": {
"key_workspace_id_id_pk": {
"name": "key_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -653,10 +628,7 @@
"indexes": {
"model_workspace_model": {
"name": "model_workspace_model",
"columns": [
"workspace_id",
"model"
],
"columns": ["workspace_id", "model"],
"isUnique": true
}
},
@@ -664,10 +636,7 @@
"compositePrimaryKeys": {
"model_workspace_id_id_pk": {
"name": "model_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -731,10 +700,7 @@
"indexes": {
"workspace_provider": {
"name": "workspace_provider",
"columns": [
"workspace_id",
"provider"
],
"columns": ["workspace_id", "provider"],
"isUnique": true
}
},
@@ -742,10 +708,7 @@
"compositePrimaryKeys": {
"provider_workspace_id_id_pk": {
"name": "provider_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -858,32 +821,22 @@
"indexes": {
"user_account_id": {
"name": "user_account_id",
"columns": [
"workspace_id",
"account_id"
],
"columns": ["workspace_id", "account_id"],
"isUnique": true
},
"user_email": {
"name": "user_email",
"columns": [
"workspace_id",
"email"
],
"columns": ["workspace_id", "email"],
"isUnique": true
},
"global_account_id": {
"name": "global_account_id",
"columns": [
"account_id"
],
"columns": ["account_id"],
"isUnique": false
},
"global_email": {
"name": "global_email",
"columns": [
"email"
],
"columns": ["email"],
"isUnique": false
}
},
@@ -891,10 +844,7 @@
"compositePrimaryKeys": {
"user_workspace_id_id_pk": {
"name": "user_workspace_id_id_pk",
"columns": [
"workspace_id",
"id"
]
"columns": ["workspace_id", "id"]
}
},
"uniqueConstraints": {},
@@ -951,9 +901,7 @@
"indexes": {
"slug": {
"name": "slug",
"columns": [
"slug"
],
"columns": ["slug"],
"isUnique": true
}
},
@@ -961,9 +909,7 @@
"compositePrimaryKeys": {
"workspace_id": {
"name": "workspace_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -980,4 +926,4 @@
"tables": {},
"indexes": {}
}
}
}
@@ -269,4 +269,4 @@
"breakpoints": true
}
]
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.0.18",
"version": "1.0.44",
"private": true,
"type": "module",
"dependencies": {
+28 -25
View File
@@ -24,37 +24,40 @@ export namespace AWS {
body: z.string(),
}),
async (input) => {
const res = await createClient().fetch("https://email.us-east-1.amazonaws.com/v2/email/outbound-emails", {
method: "POST",
headers: {
"X-Amz-Target": "SES.SendEmail",
"Content-Type": "application/json",
},
body: JSON.stringify({
FromEmailAddress: `OpenCode Zen <contact@anoma.ly>`,
Destination: {
ToAddresses: [input.to],
const res = await createClient().fetch(
"https://email.us-east-1.amazonaws.com/v2/email/outbound-emails",
{
method: "POST",
headers: {
"X-Amz-Target": "SES.SendEmail",
"Content-Type": "application/json",
},
Content: {
Simple: {
Subject: {
Charset: "UTF-8",
Data: input.subject,
},
Body: {
Text: {
body: JSON.stringify({
FromEmailAddress: `OpenCode Zen <contact@anoma.ly>`,
Destination: {
ToAddresses: [input.to],
},
Content: {
Simple: {
Subject: {
Charset: "UTF-8",
Data: input.body,
Data: input.subject,
},
Html: {
Charset: "UTF-8",
Data: input.body,
Body: {
Text: {
Charset: "UTF-8",
Data: input.body,
},
Html: {
Charset: "UTF-8",
Data: input.body,
},
},
},
},
},
}),
})
}),
},
)
if (!res.ok) {
throw new Error(`Failed to send email: ${res.statusText}`)
}
+38 -23
View File
@@ -10,13 +10,12 @@ import { centsToMicroCents } from "./util/price"
import { User } from "./user"
export namespace Billing {
export const CHARGE_NAME = "opencode credits"
export const CHARGE_FEE_NAME = "processing fee"
export const CHARGE_AMOUNT = 2000 // $20
export const CHARGE_AMOUNT_DOLLAR = 20
export const CHARGE_FEE = 123 // Stripe fee 4.4% + $0.30
export const CHARGE_THRESHOLD_DOLLAR = 5
export const CHARGE_THRESHOLD = 500 // $5
export const ITEM_CREDIT_NAME = "opencode credits"
export const ITEM_FEE_NAME = "processing fee"
export const RELOAD_AMOUNT = 20
export const RELOAD_AMOUNT_MIN = 10
export const RELOAD_TRIGGER = 5
export const RELOAD_TRIGGER_MIN = 5
export const stripe = () =>
new Stripe(Resource.STRIPE_SECRET_KEY.value, {
apiVersion: "2025-03-31.basil",
@@ -33,6 +32,8 @@ export namespace Billing {
paymentMethodLast4: BillingTable.paymentMethodLast4,
balance: BillingTable.balance,
reload: BillingTable.reload,
reloadAmount: BillingTable.reloadAmount,
reloadTrigger: BillingTable.reloadTrigger,
monthlyLimit: BillingTable.monthlyLimit,
monthlyUsage: BillingTable.monthlyUsage,
timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated,
@@ -67,17 +68,28 @@ export namespace Billing {
)
}
export const calculateFeeInCents = (x: number) => {
// math: x = total - (total * 0.044 + 0.30)
// math: x = total * (1-0.044) - 0.30
// math: (x + 0.30) / 0.956 = total
return Math.round(((x + 30) / 0.956) * 0.044 + 30)
}
export const reload = async () => {
const { customerID, paymentMethodID } = await Database.use((tx) =>
const billing = await Database.use((tx) =>
tx
.select({
customerID: BillingTable.customerID,
paymentMethodID: BillingTable.paymentMethodID,
reloadAmount: BillingTable.reloadAmount,
})
.from(BillingTable)
.where(eq(BillingTable.workspaceID, Actor.workspace()))
.then((rows) => rows[0]),
)
const customerID = billing.customerID
const paymentMethodID = billing.paymentMethodID
const amountInCents = (billing.reloadAmount ?? Billing.RELOAD_AMOUNT) * 100
const paymentID = Identifier.create("payment")
let invoice
try {
@@ -89,18 +101,18 @@ export namespace Billing {
currency: "usd",
})
await Billing.stripe().invoiceItems.create({
amount: Billing.CHARGE_AMOUNT,
amount: amountInCents,
currency: "usd",
customer: customerID!,
description: CHARGE_NAME,
invoice: draft.id!,
description: ITEM_CREDIT_NAME,
})
await Billing.stripe().invoiceItems.create({
amount: Billing.CHARGE_FEE,
amount: calculateFeeInCents(amountInCents),
currency: "usd",
customer: customerID!,
description: CHARGE_FEE_NAME,
invoice: draft.id!,
description: ITEM_FEE_NAME,
})
await Billing.stripe().invoices.finalizeInvoice(draft.id!)
invoice = await Billing.stripe().invoices.pay(draft.id!, {
@@ -128,7 +140,7 @@ export namespace Billing {
await tx
.update(BillingTable)
.set({
balance: sql`${BillingTable.balance} + ${centsToMicroCents(CHARGE_AMOUNT)}`,
balance: sql`${BillingTable.balance} + ${centsToMicroCents(amountInCents)}`,
reloadError: null,
timeReloadError: null,
})
@@ -136,7 +148,7 @@ export namespace Billing {
await tx.insert(PaymentTable).values({
workspaceID: Actor.workspace(),
id: paymentID,
amount: centsToMicroCents(CHARGE_AMOUNT),
amount: centsToMicroCents(amountInCents),
invoiceID: invoice.id!,
paymentID: invoice.payments?.data[0].payment.payment_intent as string,
customerID,
@@ -159,13 +171,19 @@ export namespace Billing {
z.object({
successUrl: z.string(),
cancelUrl: z.string(),
amount: z.number().optional(),
}),
async (input) => {
const user = Actor.assert("user")
const { successUrl, cancelUrl } = input
const { successUrl, cancelUrl, amount } = input
if (amount !== undefined && amount < Billing.RELOAD_AMOUNT_MIN) {
throw new Error(`Amount must be at least $${Billing.RELOAD_AMOUNT_MIN}`)
}
const email = await User.getAuthEmail(user.properties.userID)
const customer = await Billing.get()
const amountInCents = (amount ?? customer.reloadAmount ?? Billing.RELOAD_AMOUNT) * 100
const session = await Billing.stripe().checkout.sessions.create({
mode: "payment",
billing_address_collection: "required",
@@ -173,20 +191,16 @@ export namespace Billing {
{
price_data: {
currency: "usd",
product_data: {
name: CHARGE_NAME,
},
unit_amount: CHARGE_AMOUNT,
product_data: { name: ITEM_CREDIT_NAME },
unit_amount: amountInCents,
},
quantity: 1,
},
{
price_data: {
currency: "usd",
product_data: {
name: CHARGE_FEE_NAME,
},
unit_amount: CHARGE_FEE,
product_data: { name: ITEM_FEE_NAME },
unit_amount: calculateFeeInCents(amountInCents),
},
quantity: 1,
},
@@ -218,6 +232,7 @@ export namespace Billing {
},
metadata: {
workspaceID: Actor.workspace(),
amount: amountInCents.toString(),
},
success_url: successUrl,
cancel_url: cancelUrl,
+8 -2
View File
@@ -5,7 +5,10 @@ import { Client } from "@planetscale/database"
import { MySqlTransaction, type MySqlTransactionConfig } from "drizzle-orm/mysql-core"
import type { ExtractTablesWithRelations } from "drizzle-orm"
import type { PlanetScalePreparedQueryHKT, PlanetscaleQueryResultHKT } from "drizzle-orm/planetscale-serverless"
import type {
PlanetScalePreparedQueryHKT,
PlanetscaleQueryResultHKT,
} from "drizzle-orm/planetscale-serverless"
import { Context } from "../context"
import { memo } from "../util/memo"
@@ -67,7 +70,10 @@ export namespace Database {
}
}
export async function transaction<T>(callback: (tx: TxOrDb) => Promise<T>, config?: MySqlTransactionConfig) {
export async function transaction<T>(
callback: (tx: TxOrDb) => Promise<T>,
config?: MySqlTransactionConfig,
) {
try {
const { tx } = TransactionContext.use()
return callback(tx)
+8 -2
View File
@@ -20,8 +20,14 @@ export namespace Key {
email: AuthTable.subject,
})
.from(KeyTable)
.innerJoin(UserTable, and(eq(KeyTable.userID, UserTable.id), eq(KeyTable.workspaceID, UserTable.workspaceID)))
.innerJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")))
.innerJoin(
UserTable,
and(eq(KeyTable.userID, UserTable.id), eq(KeyTable.workspaceID, UserTable.workspaceID)),
)
.innerJoin(
AuthTable,
and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")),
)
.where(
and(
...[
+4
View File
@@ -8,6 +8,9 @@ import { Actor } from "./actor"
import { Resource } from "@opencode-ai/console-resource"
export namespace ZenData {
const FormatSchema = z.enum(["anthropic", "openai", "oa-compat"])
export type Format = z.infer<typeof FormatSchema>
const ModelCostSchema = z.object({
input: z.number(),
output: z.number(),
@@ -34,6 +37,7 @@ export namespace ZenData {
const ProviderSchema = z.object({
api: z.string(),
apiKey: z.string(),
format: FormatSchema,
headerMappings: z.record(z.string(), z.string()).optional(),
})
+9 -2
View File
@@ -11,7 +11,9 @@ export namespace Provider {
tx
.select()
.from(ProviderTable)
.where(and(eq(ProviderTable.workspaceID, Actor.workspace()), isNull(ProviderTable.timeDeleted))),
.where(
and(eq(ProviderTable.workspaceID, Actor.workspace()), isNull(ProviderTable.timeDeleted)),
),
),
)
@@ -50,7 +52,12 @@ export namespace Provider {
return Database.transaction((tx) =>
tx
.delete(ProviderTable)
.where(and(eq(ProviderTable.provider, provider), eq(ProviderTable.workspaceID, Actor.workspace()))),
.where(
and(
eq(ProviderTable.provider, provider),
eq(ProviderTable.workspaceID, Actor.workspace()),
),
),
)
},
)
+8 -1
View File
@@ -1,4 +1,11 @@
import { index, mysqlEnum, mysqlTable, primaryKey, uniqueIndex, varchar } from "drizzle-orm/mysql-core"
import {
index,
mysqlEnum,
mysqlTable,
primaryKey,
uniqueIndex,
varchar,
} from "drizzle-orm/mysql-core"
import { id, timestamps, ulid } from "../drizzle/types"
export const AuthProvider = ["email", "github", "google"] as const
@@ -9,5 +9,8 @@ export const ModelTable = mysqlTable(
...timestamps,
model: varchar("model", { length: 64 }).notNull(),
},
(table) => [...workspaceIndexes(table), uniqueIndex("model_workspace_model").on(table.workspaceID, table.model)],
(table) => [
...workspaceIndexes(table),
uniqueIndex("model_workspace_model").on(table.workspaceID, table.model),
],
)
@@ -10,5 +10,8 @@ export const ProviderTable = mysqlTable(
provider: varchar("provider", { length: 64 }).notNull(),
credentials: text("credentials").notNull(),
},
(table) => [...workspaceIndexes(table), uniqueIndex("workspace_provider").on(table.workspaceID, table.provider)],
(table) => [
...workspaceIndexes(table),
uniqueIndex("workspace_provider").on(table.workspaceID, table.provider),
],
)
+9 -1
View File
@@ -1,4 +1,12 @@
import { mysqlTable, uniqueIndex, varchar, int, mysqlEnum, index, bigint } from "drizzle-orm/mysql-core"
import {
mysqlTable,
uniqueIndex,
varchar,
int,
mysqlEnum,
index,
bigint,
} from "drizzle-orm/mysql-core"
import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types"
import { workspaceIndexes } from "./workspace.sql"
+23 -5
View File
@@ -26,7 +26,10 @@ export namespace User {
authEmail: AuthTable.subject,
})
.from(UserTable)
.leftJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")))
.leftJoin(
AuthTable,
and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")),
)
.where(and(eq(UserTable.workspaceID, Actor.workspace()), isNull(UserTable.timeDeleted))),
),
)
@@ -36,7 +39,13 @@ export namespace User {
tx
.select()
.from(UserTable)
.where(and(eq(UserTable.workspaceID, Actor.workspace()), eq(UserTable.id, id), isNull(UserTable.timeDeleted)))
.where(
and(
eq(UserTable.workspaceID, Actor.workspace()),
eq(UserTable.id, id),
isNull(UserTable.timeDeleted),
),
)
.then((rows) => rows[0]),
),
)
@@ -48,7 +57,10 @@ export namespace User {
email: AuthTable.subject,
})
.from(UserTable)
.leftJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")))
.leftJoin(
AuthTable,
and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")),
)
.where(and(eq(UserTable.workspaceID, Actor.workspace()), eq(UserTable.id, id)))
.then((rows) => rows[0]?.email),
),
@@ -130,10 +142,16 @@ export namespace User {
workspaceName: WorkspaceTable.name,
})
.from(UserTable)
.innerJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")))
.innerJoin(
AuthTable,
and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")),
)
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, workspaceID))
.where(
and(eq(UserTable.workspaceID, workspaceID), eq(UserTable.id, Actor.assert("user").properties.userID)),
and(
eq(UserTable.workspaceID, workspaceID),
eq(UserTable.id, Actor.assert("user").properties.userID),
),
)
.then((rows) => rows[0]),
)
+69 -69
View File
@@ -6,99 +6,99 @@
import "sst"
declare module "sst" {
export interface Resource {
"ADMIN_SECRET": {
"type": "sst.sst.Secret"
"value": string
ADMIN_SECRET: {
type: "sst.sst.Secret"
value: string
}
"AUTH_API_URL": {
"type": "sst.sst.Linkable"
"value": string
AUTH_API_URL: {
type: "sst.sst.Linkable"
value: string
}
"AWS_SES_ACCESS_KEY_ID": {
"type": "sst.sst.Secret"
"value": string
AWS_SES_ACCESS_KEY_ID: {
type: "sst.sst.Secret"
value: string
}
"AWS_SES_SECRET_ACCESS_KEY": {
"type": "sst.sst.Secret"
"value": string
AWS_SES_SECRET_ACCESS_KEY: {
type: "sst.sst.Secret"
value: string
}
"Console": {
"type": "sst.cloudflare.SolidStart"
"url": string
Console: {
type: "sst.cloudflare.SolidStart"
url: string
}
"Database": {
"database": string
"host": string
"password": string
"port": number
"type": "sst.sst.Linkable"
"username": string
Database: {
database: string
host: string
password: string
port: number
type: "sst.sst.Linkable"
username: string
}
"Desktop": {
"type": "sst.cloudflare.StaticSite"
"url": string
Desktop: {
type: "sst.cloudflare.StaticSite"
url: string
}
"EMAILOCTOPUS_API_KEY": {
"type": "sst.sst.Secret"
"value": string
EMAILOCTOPUS_API_KEY: {
type: "sst.sst.Secret"
value: string
}
"GITHUB_APP_ID": {
"type": "sst.sst.Secret"
"value": string
GITHUB_APP_ID: {
type: "sst.sst.Secret"
value: string
}
"GITHUB_APP_PRIVATE_KEY": {
"type": "sst.sst.Secret"
"value": string
GITHUB_APP_PRIVATE_KEY: {
type: "sst.sst.Secret"
value: string
}
"GITHUB_CLIENT_ID_CONSOLE": {
"type": "sst.sst.Secret"
"value": string
GITHUB_CLIENT_ID_CONSOLE: {
type: "sst.sst.Secret"
value: string
}
"GITHUB_CLIENT_SECRET_CONSOLE": {
"type": "sst.sst.Secret"
"value": string
GITHUB_CLIENT_SECRET_CONSOLE: {
type: "sst.sst.Secret"
value: string
}
"GOOGLE_CLIENT_ID": {
"type": "sst.sst.Secret"
"value": string
GOOGLE_CLIENT_ID: {
type: "sst.sst.Secret"
value: string
}
"HONEYCOMB_API_KEY": {
"type": "sst.sst.Secret"
"value": string
HONEYCOMB_API_KEY: {
type: "sst.sst.Secret"
value: string
}
"STRIPE_SECRET_KEY": {
"type": "sst.sst.Secret"
"value": string
STRIPE_SECRET_KEY: {
type: "sst.sst.Secret"
value: string
}
"STRIPE_WEBHOOK_SECRET": {
"type": "sst.sst.Linkable"
"value": string
STRIPE_WEBHOOK_SECRET: {
type: "sst.sst.Linkable"
value: string
}
"Web": {
"type": "sst.cloudflare.Astro"
"url": string
Web: {
type: "sst.cloudflare.Astro"
url: string
}
"ZEN_MODELS1": {
"type": "sst.sst.Secret"
"value": string
ZEN_MODELS1: {
type: "sst.sst.Secret"
value: string
}
"ZEN_MODELS2": {
"type": "sst.sst.Secret"
"value": string
ZEN_MODELS2: {
type: "sst.sst.Secret"
value: string
}
}
}
// cloudflare
import * as cloudflare from "@cloudflare/workers-types";
// cloudflare
import * as cloudflare from "@cloudflare/workers-types"
declare module "sst" {
export interface Resource {
"Api": cloudflare.Service
"AuthApi": cloudflare.Service
"AuthStorage": cloudflare.KVNamespace
"Bucket": cloudflare.R2Bucket
"LogProcessor": cloudflare.Service
Api: cloudflare.Service
AuthApi: cloudflare.Service
AuthStorage: cloudflare.KVNamespace
Bucket: cloudflare.R2Bucket
LogProcessor: cloudflare.Service
}
}
import "sst"
export {}
export {}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.0.18",
"version": "1.0.44",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+69 -69
View File
@@ -6,99 +6,99 @@
import "sst"
declare module "sst" {
export interface Resource {
"ADMIN_SECRET": {
"type": "sst.sst.Secret"
"value": string
ADMIN_SECRET: {
type: "sst.sst.Secret"
value: string
}
"AUTH_API_URL": {
"type": "sst.sst.Linkable"
"value": string
AUTH_API_URL: {
type: "sst.sst.Linkable"
value: string
}
"AWS_SES_ACCESS_KEY_ID": {
"type": "sst.sst.Secret"
"value": string
AWS_SES_ACCESS_KEY_ID: {
type: "sst.sst.Secret"
value: string
}
"AWS_SES_SECRET_ACCESS_KEY": {
"type": "sst.sst.Secret"
"value": string
AWS_SES_SECRET_ACCESS_KEY: {
type: "sst.sst.Secret"
value: string
}
"Console": {
"type": "sst.cloudflare.SolidStart"
"url": string
Console: {
type: "sst.cloudflare.SolidStart"
url: string
}
"Database": {
"database": string
"host": string
"password": string
"port": number
"type": "sst.sst.Linkable"
"username": string
Database: {
database: string
host: string
password: string
port: number
type: "sst.sst.Linkable"
username: string
}
"Desktop": {
"type": "sst.cloudflare.StaticSite"
"url": string
Desktop: {
type: "sst.cloudflare.StaticSite"
url: string
}
"EMAILOCTOPUS_API_KEY": {
"type": "sst.sst.Secret"
"value": string
EMAILOCTOPUS_API_KEY: {
type: "sst.sst.Secret"
value: string
}
"GITHUB_APP_ID": {
"type": "sst.sst.Secret"
"value": string
GITHUB_APP_ID: {
type: "sst.sst.Secret"
value: string
}
"GITHUB_APP_PRIVATE_KEY": {
"type": "sst.sst.Secret"
"value": string
GITHUB_APP_PRIVATE_KEY: {
type: "sst.sst.Secret"
value: string
}
"GITHUB_CLIENT_ID_CONSOLE": {
"type": "sst.sst.Secret"
"value": string
GITHUB_CLIENT_ID_CONSOLE: {
type: "sst.sst.Secret"
value: string
}
"GITHUB_CLIENT_SECRET_CONSOLE": {
"type": "sst.sst.Secret"
"value": string
GITHUB_CLIENT_SECRET_CONSOLE: {
type: "sst.sst.Secret"
value: string
}
"GOOGLE_CLIENT_ID": {
"type": "sst.sst.Secret"
"value": string
GOOGLE_CLIENT_ID: {
type: "sst.sst.Secret"
value: string
}
"HONEYCOMB_API_KEY": {
"type": "sst.sst.Secret"
"value": string
HONEYCOMB_API_KEY: {
type: "sst.sst.Secret"
value: string
}
"STRIPE_SECRET_KEY": {
"type": "sst.sst.Secret"
"value": string
STRIPE_SECRET_KEY: {
type: "sst.sst.Secret"
value: string
}
"STRIPE_WEBHOOK_SECRET": {
"type": "sst.sst.Linkable"
"value": string
STRIPE_WEBHOOK_SECRET: {
type: "sst.sst.Linkable"
value: string
}
"Web": {
"type": "sst.cloudflare.Astro"
"url": string
Web: {
type: "sst.cloudflare.Astro"
url: string
}
"ZEN_MODELS1": {
"type": "sst.sst.Secret"
"value": string
ZEN_MODELS1: {
type: "sst.sst.Secret"
value: string
}
"ZEN_MODELS2": {
"type": "sst.sst.Secret"
"value": string
ZEN_MODELS2: {
type: "sst.sst.Secret"
value: string
}
}
}
// cloudflare
import * as cloudflare from "@cloudflare/workers-types";
// cloudflare
import * as cloudflare from "@cloudflare/workers-types"
declare module "sst" {
export interface Resource {
"Api": cloudflare.Service
"AuthApi": cloudflare.Service
"AuthStorage": cloudflare.KVNamespace
"Bucket": cloudflare.R2Bucket
"LogProcessor": cloudflare.Service
Api: cloudflare.Service
AuthApi: cloudflare.Service
AuthStorage: cloudflare.KVNamespace
Bucket: cloudflare.R2Bucket
LogProcessor: cloudflare.Service
}
}
import "sst"
export {}
export {}
@@ -1,6 +1,18 @@
// @ts-nocheck
import React from "react"
import { Img, Row, Html, Link, Body, Head, Button, Column, Preview, Section, Container } from "@jsx-email/all"
import {
Img,
Row,
Html,
Link,
Body,
Head,
Button,
Column,
Preview,
Section,
Container,
} from "@jsx-email/all"
import { Text, Fonts, Title, A, Span } from "../components"
import {
unit,
@@ -52,8 +64,8 @@ export const InviteEmail = ({
<Section style={{ padding: `${unit * 2}px 0 0 0` }}>
<Text style={headingText}>Join your team's OpenCode workspace</Text>
<Text style={contentText}>
You have been invited by <Span style={contentHighlightText}>{inviter}</Span> to join the{" "}
<Span style={contentHighlightText}>{workspaceName}</Span> workspace on OpenCode.
You have been invited by <Span style={contentHighlightText}>{inviter}</Span> to join
the <Span style={contentHighlightText}>{workspaceName}</Span> workspace on OpenCode.
</Text>
</Section>
@@ -61,7 +73,12 @@ export const InviteEmail = ({
<Button style={button} href={url}>
<Text style={buttonText}>
Join workspace
<Img width="24" height="24" src={`${assetsUrl}/right-arrow.png`} alt="Arrow right" />
<Img
width="24"
height="24"
src={`${assetsUrl}/right-arrow.png`}
alt="Arrow right"
/>
</Text>
</Button>
</Section>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.0.18",
"version": "1.0.44",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
+1 -1
View File
@@ -6,4 +6,4 @@
/// <reference path="../../../sst-env.d.ts" />
import "sst"
export {}
export {}
+69 -69
View File
@@ -6,99 +6,99 @@
import "sst"
declare module "sst" {
export interface Resource {
"ADMIN_SECRET": {
"type": "sst.sst.Secret"
"value": string
ADMIN_SECRET: {
type: "sst.sst.Secret"
value: string
}
"AUTH_API_URL": {
"type": "sst.sst.Linkable"
"value": string
AUTH_API_URL: {
type: "sst.sst.Linkable"
value: string
}
"AWS_SES_ACCESS_KEY_ID": {
"type": "sst.sst.Secret"
"value": string
AWS_SES_ACCESS_KEY_ID: {
type: "sst.sst.Secret"
value: string
}
"AWS_SES_SECRET_ACCESS_KEY": {
"type": "sst.sst.Secret"
"value": string
AWS_SES_SECRET_ACCESS_KEY: {
type: "sst.sst.Secret"
value: string
}
"Console": {
"type": "sst.cloudflare.SolidStart"
"url": string
Console: {
type: "sst.cloudflare.SolidStart"
url: string
}
"Database": {
"database": string
"host": string
"password": string
"port": number
"type": "sst.sst.Linkable"
"username": string
Database: {
database: string
host: string
password: string
port: number
type: "sst.sst.Linkable"
username: string
}
"Desktop": {
"type": "sst.cloudflare.StaticSite"
"url": string
Desktop: {
type: "sst.cloudflare.StaticSite"
url: string
}
"EMAILOCTOPUS_API_KEY": {
"type": "sst.sst.Secret"
"value": string
EMAILOCTOPUS_API_KEY: {
type: "sst.sst.Secret"
value: string
}
"GITHUB_APP_ID": {
"type": "sst.sst.Secret"
"value": string
GITHUB_APP_ID: {
type: "sst.sst.Secret"
value: string
}
"GITHUB_APP_PRIVATE_KEY": {
"type": "sst.sst.Secret"
"value": string
GITHUB_APP_PRIVATE_KEY: {
type: "sst.sst.Secret"
value: string
}
"GITHUB_CLIENT_ID_CONSOLE": {
"type": "sst.sst.Secret"
"value": string
GITHUB_CLIENT_ID_CONSOLE: {
type: "sst.sst.Secret"
value: string
}
"GITHUB_CLIENT_SECRET_CONSOLE": {
"type": "sst.sst.Secret"
"value": string
GITHUB_CLIENT_SECRET_CONSOLE: {
type: "sst.sst.Secret"
value: string
}
"GOOGLE_CLIENT_ID": {
"type": "sst.sst.Secret"
"value": string
GOOGLE_CLIENT_ID: {
type: "sst.sst.Secret"
value: string
}
"HONEYCOMB_API_KEY": {
"type": "sst.sst.Secret"
"value": string
HONEYCOMB_API_KEY: {
type: "sst.sst.Secret"
value: string
}
"STRIPE_SECRET_KEY": {
"type": "sst.sst.Secret"
"value": string
STRIPE_SECRET_KEY: {
type: "sst.sst.Secret"
value: string
}
"STRIPE_WEBHOOK_SECRET": {
"type": "sst.sst.Linkable"
"value": string
STRIPE_WEBHOOK_SECRET: {
type: "sst.sst.Linkable"
value: string
}
"Web": {
"type": "sst.cloudflare.Astro"
"url": string
Web: {
type: "sst.cloudflare.Astro"
url: string
}
"ZEN_MODELS1": {
"type": "sst.sst.Secret"
"value": string
ZEN_MODELS1: {
type: "sst.sst.Secret"
value: string
}
"ZEN_MODELS2": {
"type": "sst.sst.Secret"
"value": string
ZEN_MODELS2: {
type: "sst.sst.Secret"
value: string
}
}
}
// cloudflare
import * as cloudflare from "@cloudflare/workers-types";
// cloudflare
import * as cloudflare from "@cloudflare/workers-types"
declare module "sst" {
export interface Resource {
"Api": cloudflare.Service
"AuthApi": cloudflare.Service
"AuthStorage": cloudflare.KVNamespace
"Bucket": cloudflare.R2Bucket
"LogProcessor": cloudflare.Service
Api: cloudflare.Service
AuthApi: cloudflare.Service
AuthStorage: cloudflare.KVNamespace
Bucket: cloudflare.R2Bucket
LogProcessor: cloudflare.Service
}
}
import "sst"
export {}
export {}
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/desktop",
"version": "1.0.18",
"version": "1.0.44",
"description": "",
"type": "module",
"scripts": {
@@ -31,6 +31,7 @@
"@solid-primitives/event-bus": "1.1.2",
"@solid-primitives/resize-observer": "2.1.3",
"@solid-primitives/scroll": "2.1.3",
"@solid-primitives/storage": "4.3.3",
"@solidjs/meta": "catalog:",
"@solidjs/router": "0.15.3",
"@thisbeyond/solid-dnd": "0.7.5",
-846
View File
@@ -1,846 +0,0 @@
import { bundledLanguages, type BundledLanguage, type ShikiTransformer } from "shiki"
import { splitProps, type ComponentProps, createEffect, onMount, onCleanup, createMemo, createResource } from "solid-js"
import { useLocal, type TextSelection } from "@/context/local"
import { getFileExtension, getNodeOffsetInLine, getSelectionInContainer } from "@/utils"
import { useShiki } from "@opencode-ai/ui"
type DefinedSelection = Exclude<TextSelection, undefined>
interface Props extends ComponentProps<"div"> {
code: string
path: string
}
export function Code(props: Props) {
const ctx = useLocal()
const highlighter = useShiki()
const [local, others] = splitProps(props, ["class", "classList", "code", "path"])
const lang = createMemo(() => {
const ext = getFileExtension(local.path)
if (ext in bundledLanguages) return ext
return "text"
})
let container: HTMLDivElement | undefined
let isProgrammaticSelection = false
const ranges = createMemo<DefinedSelection[]>(() => {
const items = ctx.context.all() as Array<{ type: "file"; path: string; selection?: DefinedSelection }>
const result: DefinedSelection[] = []
for (const item of items) {
if (item.path !== local.path) continue
const selection = item.selection
if (!selection) continue
result.push(selection)
}
return result
})
const createLineNumberTransformer = (selections: DefinedSelection[]): ShikiTransformer => {
const highlighted = new Set<number>()
for (const selection of selections) {
const startLine = selection.startLine
const endLine = selection.endLine
const start = Math.max(1, Math.min(startLine, endLine))
const end = Math.max(start, Math.max(startLine, endLine))
const count = end - start + 1
if (count <= 0) continue
const values = Array.from({ length: count }, (_, index) => start + index)
for (const value of values) highlighted.add(value)
}
return {
name: "line-number-highlight",
line(node, index) {
if (!highlighted.has(index)) return
this.addClassToHast(node, "line-number-highlight")
const children = node.children
if (!Array.isArray(children)) return
for (const child of children) {
if (!child || typeof child !== "object") continue
const element = child as { type?: string; properties?: { className?: string[] } }
if (element.type !== "element") continue
const className = element.properties?.className
if (!Array.isArray(className)) continue
const matches = className.includes("diff-oldln") || className.includes("diff-newln")
if (!matches) continue
if (className.includes("line-number-highlight")) continue
className.push("line-number-highlight")
}
},
}
}
const [html] = createResource(
() => ranges(),
async (activeRanges) => {
if (!highlighter.getLoadedLanguages().includes(lang())) {
await highlighter.loadLanguage(lang() as BundledLanguage)
}
return highlighter.codeToHtml(local.code || "", {
lang: lang() && lang() in bundledLanguages ? lang() : "text",
theme: "opencode",
transformers: [transformerUnifiedDiff(), transformerDiffGroups(), createLineNumberTransformer(activeRanges)],
}) as string
},
)
onMount(() => {
if (!container) return
let ticking = false
const onScroll = () => {
if (!container) return
// if (ctx.file.active()?.path !== local.path) return
if (ticking) return
ticking = true
requestAnimationFrame(() => {
ticking = false
ctx.file.scroll(local.path, container!.scrollTop)
})
}
const onSelectionChange = () => {
if (!container) return
if (isProgrammaticSelection) return
// if (ctx.file.active()?.path !== local.path) return
const d = getSelectionInContainer(container)
if (!d) return
const p = ctx.file.node(local.path)?.selection
if (p && p.startLine === d.sl && p.endLine === d.el && p.startChar === d.sch && p.endChar === d.ech) return
ctx.file.select(local.path, { startLine: d.sl, startChar: d.sch, endLine: d.el, endChar: d.ech })
}
const MOD = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform) ? "Meta" : "Control"
const onKeyDown = (e: KeyboardEvent) => {
// if (ctx.file.active()?.path !== local.path) return
const ae = document.activeElement as HTMLElement | undefined
const tag = (ae?.tagName || "").toLowerCase()
const inputFocused = !!ae && (tag === "input" || tag === "textarea" || ae.isContentEditable)
if (inputFocused) return
if (e.getModifierState(MOD) && e.key.toLowerCase() === "a") {
e.preventDefault()
if (!container) return
const element = container.querySelector("code") as HTMLElement | undefined
if (!element) return
const lines = Array.from(element.querySelectorAll(".line"))
if (!lines.length) return
const r = document.createRange()
const last = lines[lines.length - 1]
r.selectNodeContents(last)
const lastLen = r.toString().length
ctx.file.select(local.path, { startLine: 1, startChar: 0, endLine: lines.length, endChar: lastLen })
}
}
container.addEventListener("scroll", onScroll)
document.addEventListener("selectionchange", onSelectionChange)
document.addEventListener("keydown", onKeyDown)
onCleanup(() => {
container?.removeEventListener("scroll", onScroll)
document.removeEventListener("selectionchange", onSelectionChange)
document.removeEventListener("keydown", onKeyDown)
})
})
// Restore scroll position from store when content is ready
createEffect(() => {
const content = html()
if (!container || !content) return
const top = ctx.file.node(local.path)?.scrollTop
if (top !== undefined && container.scrollTop !== top) container.scrollTop = top
})
// Sync selection from store -> DOM
createEffect(() => {
const content = html()
if (!container || !content) return
// if (ctx.file.active()?.path !== local.path) return
const codeEl = container.querySelector("code") as HTMLElement | undefined
if (!codeEl) return
const target = ctx.file.node(local.path)?.selection
const current = getSelectionInContainer(container)
const sel = window.getSelection()
if (!sel) return
if (!target) {
if (current) {
isProgrammaticSelection = true
sel.removeAllRanges()
queueMicrotask(() => {
isProgrammaticSelection = false
})
}
return
}
const matches = !!(
current &&
current.sl === target.startLine &&
current.sch === target.startChar &&
current.el === target.endLine &&
current.ech === target.endChar
)
if (matches) return
const lines = Array.from(codeEl.querySelectorAll(".line"))
if (lines.length === 0) return
let sIdx = Math.max(0, target.startLine - 1)
let eIdx = Math.max(0, target.endLine - 1)
let sChar = Math.max(0, target.startChar || 0)
let eChar = Math.max(0, target.endChar || 0)
if (sIdx > eIdx || (sIdx === eIdx && sChar > eChar)) {
const ti = sIdx
sIdx = eIdx
eIdx = ti
const tc = sChar
sChar = eChar
eChar = tc
}
if (eChar === 0 && eIdx > sIdx) {
eIdx = eIdx - 1
eChar = Number.POSITIVE_INFINITY
}
if (sIdx >= lines.length) return
if (eIdx >= lines.length) eIdx = lines.length - 1
const s = getNodeOffsetInLine(lines[sIdx], sChar) ?? { node: lines[sIdx], offset: 0 }
const e = getNodeOffsetInLine(lines[eIdx], eChar) ?? { node: lines[eIdx], offset: lines[eIdx].childNodes.length }
const range = document.createRange()
range.setStart(s.node, s.offset)
range.setEnd(e.node, e.offset)
isProgrammaticSelection = true
sel.removeAllRanges()
sel.addRange(range)
queueMicrotask(() => {
isProgrammaticSelection = false
})
})
// Build/toggle split layout and apply folding (both unified and split)
createEffect(() => {
const content = html()
if (!container || !content) return
const view = ctx.file.view(local.path)
const pres = Array.from(container.querySelectorAll<HTMLPreElement>("pre"))
if (pres.length === 0) return
const originalPre = pres[0]
const split = container.querySelector<HTMLElement>(".diff-split")
if (view === "diff-split") {
applySplitDiff(container)
const next = container.querySelector<HTMLElement>(".diff-split")
if (next) next.style.display = ""
originalPre.style.display = "none"
} else {
if (split) split.style.display = "none"
originalPre.style.display = ""
}
const expanded = ctx.file.folded(local.path)
if (view === "diff-split") {
const left = container.querySelector<HTMLElement>(".diff-split pre:nth-child(1) code")
const right = container.querySelector<HTMLElement>(".diff-split pre:nth-child(2) code")
if (left)
applyDiffFolding(left, 3, { expanded, onExpand: (key) => ctx.file.unfold(local.path, key), side: "left" })
if (right)
applyDiffFolding(right, 3, { expanded, onExpand: (key) => ctx.file.unfold(local.path, key), side: "right" })
} else {
const code = container.querySelector<HTMLElement>("pre code")
if (code)
applyDiffFolding(code, 3, {
expanded,
onExpand: (key) => ctx.file.unfold(local.path, key),
})
}
})
// Highlight groups + scroll coupling
const clearHighlights = () => {
if (!container) return
container.querySelectorAll<HTMLElement>(".diff-selected").forEach((el) => el.classList.remove("diff-selected"))
}
const applyHighlight = (idx: number, scroll?: boolean) => {
if (!container) return
const view = ctx.file.view(local.path)
if (view === "raw") return
clearHighlights()
const nodes: HTMLElement[] = []
if (view === "diff-split") {
const left = container.querySelector<HTMLElement>(".diff-split pre:nth-child(1) code")
const right = container.querySelector<HTMLElement>(".diff-split pre:nth-child(2) code")
if (left)
nodes.push(...Array.from(left.querySelectorAll<HTMLElement>(`[data-chgrp="${idx}"][data-diff="remove"]`)))
if (right)
nodes.push(...Array.from(right.querySelectorAll<HTMLElement>(`[data-chgrp="${idx}"][data-diff="add"]`)))
} else {
const code = container.querySelector<HTMLElement>("pre code")
if (code) nodes.push(...Array.from(code.querySelectorAll<HTMLElement>(`[data-chgrp="${idx}"]`)))
}
for (const n of nodes) n.classList.add("diff-selected")
if (scroll && nodes.length) nodes[0].scrollIntoView({ block: "center", behavior: "smooth" })
}
const countGroups = () => {
if (!container) return 0
const code = container.querySelector<HTMLElement>("pre code")
if (!code) return 0
const set = new Set<string>()
for (const el of Array.from(code.querySelectorAll<HTMLElement>(".diff-line[data-chgrp]"))) {
const v = el.getAttribute("data-chgrp")
if (v != undefined) set.add(v)
}
return set.size
}
let lastIdx: number | undefined = undefined
let lastView: string | undefined
let lastContent: string | undefined
let lastRawIdx: number | undefined = undefined
createEffect(() => {
const content = html()
if (!container || !content) return
const view = ctx.file.view(local.path)
const raw = ctx.file.changeIndex(local.path)
if (raw === undefined) return
const total = countGroups()
if (total <= 0) return
const next = ((raw % total) + total) % total
const navigated = lastRawIdx !== undefined && lastRawIdx !== raw
if (next !== raw) {
ctx.file.setChangeIndex(local.path, next)
applyHighlight(next, true)
} else {
if (lastView !== view || lastContent !== content) applyHighlight(next)
if ((lastIdx !== undefined && lastIdx !== next) || navigated) applyHighlight(next, true)
}
lastRawIdx = raw
lastIdx = next
lastView = view
lastContent = content
})
return (
<div
ref={(el) => {
container = el
}}
innerHTML={html()}
class="
font-mono text-xs tracking-wide overflow-y-auto h-full
[&]:[counter-reset:line]
[&_pre]:focus-visible:outline-none
[&_pre]:overflow-x-auto [&_pre]:no-scrollbar
[&_code]:min-w-full [&_code]:inline-block
[&_.tab]:relative
[&_.tab::before]:content['⇥']
[&_.tab::before]:absolute
[&_.tab::before]:opacity-0
[&_.space]:relative
[&_.space::before]:content-['·']
[&_.space::before]:absolute
[&_.space::before]:opacity-0
[&_.line]:inline-block [&_.line]:w-full
[&_.line]:hover:bg-background-element
[&_.line::before]:sticky [&_.line::before]:left-0
[&_.line::before]:w-12 [&_.line::before]:pr-4
[&_.line::before]:z-10
[&_.line::before]:bg-background-panel
[&_.line::before]:text-text-muted/60
[&_.line::before]:text-right [&_.line::before]:inline-block
[&_.line::before]:select-none
[&_.line::before]:[counter-increment:line]
[&_.line::before]:content-[counter(line)]
[&_.line-number-highlight]:bg-accent/20
[&_.line-number-highlight::before]:bg-accent/40!
[&_.line-number-highlight::before]:text-background-panel!
[&_code.code-diff_.line::before]:content-['']
[&_code.code-diff_.line::before]:w-0
[&_code.code-diff_.line::before]:pr-0
[&_.diff-split_code.code-diff::before]:w-10
[&_.diff-split_.diff-newln]:left-0
[&_.diff-oldln]:sticky [&_.diff-oldln]:left-0
[&_.diff-oldln]:w-10 [&_.diff-oldln]:pr-2
[&_.diff-oldln]:z-40
[&_.diff-oldln]:text-text-muted/60
[&_.diff-oldln]:text-right [&_.diff-oldln]:inline-block
[&_.diff-oldln]:select-none
[&_.diff-oldln]:bg-background-panel
[&_.diff-newln]:sticky [&_.diff-newln]:left-10
[&_.diff-newln]:w-10 [&_.diff-newln]:pr-2
[&_.diff-newln]:z-40
[&_.diff-newln]:text-text-muted/60
[&_.diff-newln]:text-right [&_.diff-newln]:inline-block
[&_.diff-newln]:select-none
[&_.diff-newln]:bg-background-panel
[&_.diff-add]:bg-success/20!
[&_.diff-add.diff-selected]:bg-success/50!
[&_.diff-add_.diff-oldln]:bg-success!
[&_.diff-add_.diff-oldln]:text-background-panel!
[&_.diff-add_.diff-newln]:bg-success!
[&_.diff-add_.diff-newln]:text-background-panel!
[&_.diff-remove]:bg-error/20!
[&_.diff-remove.diff-selected]:bg-error/50!
[&_.diff-remove_.diff-newln]:bg-error!
[&_.diff-remove_.diff-newln]:text-background-panel!
[&_.diff-remove_.diff-oldln]:bg-error!
[&_.diff-remove_.diff-oldln]:text-background-panel!
[&_.diff-sign]:inline-block [&_.diff-sign]:px-2 [&_.diff-sign]:select-none
[&_.diff-blank]:bg-background-element
[&_.diff-blank_.diff-oldln]:bg-background-element
[&_.diff-blank_.diff-newln]:bg-background-element
[&_.diff-collapsed]:block! [&_.diff-collapsed]:w-full [&_.diff-collapsed]:relative
[&_.diff-collapsed]:select-none
[&_.diff-collapsed]:bg-info/20 [&_.diff-collapsed]:hover:bg-info/40!
[&_.diff-collapsed]:text-info/80 [&_.diff-collapsed]:hover:text-info
[&_.diff-collapsed]:text-xs
[&_.diff-collapsed_.diff-oldln]:bg-info!
[&_.diff-collapsed_.diff-newln]:bg-info!
"
classList={{
...(local.classList || {}),
[local.class ?? ""]: !!local.class,
}}
{...others}
></div>
)
}
function transformerUnifiedDiff(): ShikiTransformer {
const kinds = new Map<number, string>()
const meta = new Map<number, { old?: number; new?: number; sign?: string }>()
let isDiff = false
return {
name: "unified-diff",
preprocess(input) {
kinds.clear()
meta.clear()
isDiff = false
const ls = input.split(/\r?\n/)
const out: Array<string> = []
let oldNo = 0
let newNo = 0
let inHunk = false
for (let i = 0; i < ls.length; i++) {
const s = ls[i]
const m = s.match(/^@@\s*-(\d+)(?:,(\d+))?\s+\+(\d+)(?:,(\d+))?\s*@@/)
if (m) {
isDiff = true
inHunk = true
oldNo = parseInt(m[1], 10)
newNo = parseInt(m[3], 10)
continue
}
if (
/^diff --git /.test(s) ||
/^Index: /.test(s) ||
/^--- /.test(s) ||
/^\+\+\+ /.test(s) ||
/^[=]{3,}$/.test(s) ||
/^\*{3,}$/.test(s) ||
/^\\ No newline at end of file$/.test(s)
) {
isDiff = true
continue
}
if (!inHunk) {
out.push(s)
continue
}
if (/^\+/.test(s)) {
out.push(s)
const ln = out.length
kinds.set(ln, "add")
meta.set(ln, { new: newNo, sign: "+" })
newNo++
continue
}
if (/^-/.test(s)) {
out.push(s)
const ln = out.length
kinds.set(ln, "remove")
meta.set(ln, { old: oldNo, sign: "-" })
oldNo++
continue
}
if (/^ /.test(s)) {
out.push(s)
const ln = out.length
kinds.set(ln, "context")
meta.set(ln, { old: oldNo, new: newNo })
oldNo++
newNo++
continue
}
// fallback in hunks
out.push(s)
}
return out.join("\n").trimEnd()
},
code(node) {
if (isDiff) this.addClassToHast(node, "code-diff")
},
pre(node) {
if (isDiff) this.addClassToHast(node, "code-diff")
},
line(node, line) {
if (!isDiff) return
const kind = kinds.get(line)
if (!kind) return
const m = meta.get(line) || {}
this.addClassToHast(node, "diff-line")
this.addClassToHast(node, `diff-${kind}`)
node.properties = node.properties || {}
;(node.properties as any)["data-diff"] = kind
if (m.old != undefined) (node.properties as any)["data-old"] = String(m.old)
if (m.new != undefined) (node.properties as any)["data-new"] = String(m.new)
const oldSpan = {
type: "element",
tagName: "span",
properties: { className: ["diff-oldln"] },
children: [{ type: "text", value: m.old != undefined ? String(m.old) : " " }],
}
const newSpan = {
type: "element",
tagName: "span",
properties: { className: ["diff-newln"] },
children: [{ type: "text", value: m.new != undefined ? String(m.new) : " " }],
}
if (kind === "add" || kind === "remove" || kind === "context") {
const first = (node.children && (node.children as any[])[0]) as any
if (first && first.type === "element" && first.children && first.children.length > 0) {
const t = first.children[0]
if (t && t.type === "text" && typeof t.value === "string" && t.value.length > 0) {
const ch = t.value[0]
if (ch === "+" || ch === "-" || ch === " ") t.value = t.value.slice(1)
}
}
}
const signSpan = {
type: "element",
tagName: "span",
properties: { className: ["diff-sign"] },
children: [{ type: "text", value: (m as any).sign || " " }],
}
// @ts-expect-error hast typing across versions
node.children = [oldSpan, newSpan, signSpan, ...(node.children || [])]
},
}
}
function transformerDiffGroups(): ShikiTransformer {
let group = -1
let inGroup = false
return {
name: "diff-groups",
pre() {
group = -1
inGroup = false
},
line(node) {
const props = (node.properties || {}) as any
const kind = props["data-diff"] as string | undefined
if (kind === "add" || kind === "remove") {
if (!inGroup) {
group += 1
inGroup = true
}
;(node.properties as any)["data-chgrp"] = String(group)
} else {
inGroup = false
}
},
}
}
function applyDiffFolding(
root: HTMLElement,
context = 3,
options?: { expanded?: string[]; onExpand?: (key: string) => void; side?: "left" | "right" },
) {
if (!root.classList.contains("code-diff")) return
// Cleanup: unwrap previous collapsed blocks and remove toggles
const blocks = Array.from(root.querySelectorAll<HTMLElement>(".diff-collapsed-block"))
for (const block of blocks) {
const p = block.parentNode
if (!p) {
block.remove()
continue
}
while (block.firstChild) p.insertBefore(block.firstChild, block)
block.remove()
}
const toggles = Array.from(root.querySelectorAll<HTMLElement>(".diff-collapsed"))
for (const t of toggles) t.remove()
const lines = Array.from(root.querySelectorAll<HTMLElement>(".diff-line"))
if (lines.length === 0) return
const n = lines.length
const isChange = lines.map((l) => l.dataset["diff"] === "add" || l.dataset["diff"] === "remove")
const isContext = lines.map((l) => l.dataset["diff"] === "context")
if (!isChange.some(Boolean)) return
const visible = new Array(n).fill(false) as boolean[]
for (let i = 0; i < n; i++) if (isChange[i]) visible[i] = true
for (let i = 0; i < n; i++) {
if (isChange[i]) {
const s = Math.max(0, i - context)
const e = Math.min(n - 1, i + context)
for (let j = s; j <= e; j++) if (isContext[j]) visible[j] = true
}
}
type Range = { start: number; end: number }
const ranges: Range[] = []
let i = 0
while (i < n) {
if (!visible[i] && isContext[i]) {
let j = i
while (j + 1 < n && !visible[j + 1] && isContext[j + 1]) j++
ranges.push({ start: i, end: j })
i = j + 1
} else {
i++
}
}
for (const r of ranges) {
const start = lines[r.start]
const end = lines[r.end]
const count = r.end - r.start + 1
const minCollapse = 20
if (count < minCollapse) {
continue
}
// Wrap the entire collapsed chunk (including trailing newline) so it takes no space
const block = document.createElement("span")
block.className = "diff-collapsed-block"
start.parentElement?.insertBefore(block, start)
let cur: Node | undefined = start
while (cur) {
const next: Node | undefined = cur.nextSibling || undefined
block.appendChild(cur)
if (cur === end) {
// Also move the newline after the last line into the block
if (next && next.nodeType === Node.TEXT_NODE && (next.textContent || "").startsWith("\n")) {
block.appendChild(next)
}
break
}
cur = next
}
block.style.display = "none"
const row = document.createElement("span")
row.className = "line diff-collapsed"
row.setAttribute("data-kind", "collapsed")
row.setAttribute("data-count", String(count))
row.setAttribute("tabindex", "0")
row.setAttribute("role", "button")
const oldln = document.createElement("span")
oldln.className = "diff-oldln"
oldln.textContent = " "
const newln = document.createElement("span")
newln.className = "diff-newln"
newln.textContent = " "
const sign = document.createElement("span")
sign.className = "diff-sign"
sign.textContent = "…"
const label = document.createElement("span")
label.textContent = `show ${count} unchanged line${count > 1 ? "s" : ""}`
const key = `o${start.dataset["old"] || ""}-${end.dataset["old"] || ""}:n${start.dataset["new"] || ""}-${end.dataset["new"] || ""}`
const show = (record = true) => {
if (record) options?.onExpand?.(key)
const p = block.parentNode
if (p) {
while (block.firstChild) p.insertBefore(block.firstChild, block)
block.remove()
}
row.remove()
}
row.addEventListener("click", () => show(true))
row.addEventListener("keydown", (ev) => {
if (ev.key === "Enter" || ev.key === " ") {
ev.preventDefault()
show(true)
}
})
block.parentElement?.insertBefore(row, block)
if (!options?.side || options.side === "left") row.appendChild(oldln)
if (!options?.side || options.side === "right") row.appendChild(newln)
row.appendChild(sign)
row.appendChild(label)
if (options?.expanded && options.expanded.includes(key)) {
show(false)
}
}
}
function applySplitDiff(container: HTMLElement) {
const pres = Array.from(container.querySelectorAll<HTMLPreElement>("pre"))
if (pres.length === 0) return
const originalPre = pres[0]
const originalCode = originalPre.querySelector("code") as HTMLElement | undefined
if (!originalCode || !originalCode.classList.contains("code-diff")) return
// Rebuild split each time to match current content
const existing = container.querySelector<HTMLElement>(".diff-split")
if (existing) existing.remove()
const grid = document.createElement("div")
grid.className = "diff-split grid grid-cols-2 gap-x-6"
const makeColumn = () => {
const pre = document.createElement("pre")
pre.className = originalPre.className
const code = document.createElement("code")
code.className = originalCode.className
pre.appendChild(code)
return { pre, code }
}
const left = makeColumn()
const right = makeColumn()
// Helpers
const cloneSide = (line: HTMLElement, side: "old" | "new"): HTMLElement => {
const clone = line.cloneNode(true) as HTMLElement
const oldln = clone.querySelector(".diff-oldln")
const newln = clone.querySelector(".diff-newln")
if (side === "old") {
if (newln) newln.remove()
} else {
if (oldln) oldln.remove()
}
return clone
}
const blankLine = (side: "old" | "new", kind: "add" | "remove"): HTMLElement => {
const span = document.createElement("span")
span.className = "line diff-line diff-blank"
span.setAttribute("data-diff", kind)
const ln = document.createElement("span")
ln.className = side === "old" ? "diff-oldln" : "diff-newln"
ln.textContent = " "
span.appendChild(ln)
return span
}
const lines = Array.from(originalCode.querySelectorAll<HTMLElement>(".diff-line"))
let i = 0
while (i < lines.length) {
const cur = lines[i]
const kind = cur.dataset["diff"]
if (kind === "context") {
left.code.appendChild(cloneSide(cur, "old"))
left.code.appendChild(document.createTextNode("\n"))
right.code.appendChild(cloneSide(cur, "new"))
right.code.appendChild(document.createTextNode("\n"))
i++
continue
}
if (kind === "remove") {
// Batch consecutive removes and following adds, then pair
const removes: HTMLElement[] = []
const adds: HTMLElement[] = []
let j = i
while (j < lines.length && lines[j].dataset["diff"] === "remove") {
removes.push(lines[j])
j++
}
let k = j
while (k < lines.length && lines[k].dataset["diff"] === "add") {
adds.push(lines[k])
k++
}
const pairs = Math.min(removes.length, adds.length)
for (let p = 0; p < pairs; p++) {
left.code.appendChild(cloneSide(removes[p], "old"))
left.code.appendChild(document.createTextNode("\n"))
right.code.appendChild(cloneSide(adds[p], "new"))
right.code.appendChild(document.createTextNode("\n"))
}
for (let p = pairs; p < removes.length; p++) {
left.code.appendChild(cloneSide(removes[p], "old"))
left.code.appendChild(document.createTextNode("\n"))
right.code.appendChild(blankLine("new", "remove"))
right.code.appendChild(document.createTextNode("\n"))
}
for (let p = pairs; p < adds.length; p++) {
left.code.appendChild(blankLine("old", "add"))
left.code.appendChild(document.createTextNode("\n"))
right.code.appendChild(cloneSide(adds[p], "new"))
right.code.appendChild(document.createTextNode("\n"))
}
i = k
continue
}
if (kind === "add") {
// Run of adds not preceded by removes
const adds: HTMLElement[] = []
let j = i
while (j < lines.length && lines[j].dataset["diff"] === "add") {
adds.push(lines[j])
j++
}
for (let p = 0; p < adds.length; p++) {
left.code.appendChild(blankLine("old", "add"))
left.code.appendChild(document.createTextNode("\n"))
right.code.appendChild(cloneSide(adds[p], "new"))
right.code.appendChild(document.createTextNode("\n"))
}
i = j
continue
}
// Any other kind: mirror as context
left.code.appendChild(cloneSide(cur, "old"))
left.code.appendChild(document.createTextNode("\n"))
right.code.appendChild(cloneSide(cur, "new"))
right.code.appendChild(document.createTextNode("\n"))
i++
}
grid.appendChild(left.pre)
grid.appendChild(right.pre)
container.appendChild(grid)
}
@@ -77,7 +77,7 @@ export default function FileTree(props: {
<Collapsible
class="w-full"
forceMount={false}
open={local.file.node(node.path)?.expanded}
// open={local.file.node(node.path)?.expanded}
onOpenChange={(open) => (open ? local.file.expand(node.path) : local.file.collapse(node.path))}
>
<Collapsible.Trigger>
@@ -85,7 +85,7 @@ export default function FileTree(props: {
<Collapsible.Arrow class="text-text-muted/60 ml-1" />
<FileIcon
node={node}
expanded={local.file.node(node.path).expanded}
// expanded={local.file.node(node.path).expanded}
class="text-text-muted/60 -ml-1"
/>
</Node>

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