Compare commits

...
50 Commits
Author SHA1 Message Date
Dax Raad dd34556e9c only include severity 1 diagnostics from lsp in edit tool output
publish / publish (push) Has been cancelled
2025-07-16 15:25:37 -04:00
adamdotdevin f7dd48e60d feat(tui): more ways to quit 2025-07-16 14:20:28 -05:00
Dax Raad 93c779cf48 docs: better variable examples 2025-07-16 14:56:24 -04:00
adamdotdevin 360c04c542 docs: copying text 2025-07-16 13:26:26 -05:00
adamdotdevin 529fd57e75 fix: missing dependency
publish / publish (push) Has been cancelled
2025-07-16 12:58:29 -05:00
adamdotdevin faea3777e1 fix: missing dependency 2025-07-16 12:56:11 -05:00
Aiden Cline a4664e2344 fix: generate title should use same options as model it uses to gen (#1064) 2025-07-16 12:46:52 -05:00
adamdotdevin cdc1d8a94d feat(tui): layout config to render full width
publish / publish (push) Has been cancelled
2025-07-16 12:43:02 -05:00
Jay V fdd6d6600f docs: rename workflow 2025-07-16 13:38:00 -04:00
Jay V 9f44cfd595 docs: discord releases 2025-07-16 13:17:04 -04:00
Aiden Cline 70229b150c Fix: better title generation (needs to change due to small models) (#1059) 2025-07-16 11:47:56 -05:00
John Henry Rudden 050ff943a6 Fix: Add escape sequence for @ symbols to prevent send blocking (#1029) 2025-07-16 11:18:48 -05:00
Tom 88b58fd6a0 fix: Prevent division by zero in context percentage calculation (#1055) 2025-07-16 09:35:20 -05:00
Jeremy Mack 5d67e13df5 fix: grep omitting text after a colon (#1053) 2025-07-16 09:09:05 -05:00
Adi Yeroslav 57d1a60efc feat(tui): shift+tab to cycle modes backward (#1049) 2025-07-16 07:43:48 -05:00
Nipuna Perera add81b9739 Enhance private npm registry support (#998) 2025-07-16 08:31:38 -04:00
GitHub Action 81bdb8e269 ignore: update download stats 2025-07-16 2025-07-16 12:04:30 +00:00
adamdotdevin a563fdd287 fix(tui): diagnostics rendering 2025-07-16 06:55:14 -05:00
adamdotdevin 7c93bf5993 fix(tui): pending tool call width 2025-07-16 06:27:32 -05:00
adamdotdevin 6a5a4247c6 fix(gh): build 2025-07-16 06:13:43 -05:00
adamdotdevin a39136a2a0 fix(tui): render attachments in user messages in accent color 2025-07-16 06:09:27 -05:00
adamdotdevin 9f5b59f336 chore: messages cleanup 2025-07-16 06:09:27 -05:00
adamdotdevin 01c125b058 fix(tui): faster cache algo 2025-07-16 06:09:27 -05:00
adamdotdevin d41aa2bc72 chore(tui): simplify messages component, remove navigate, add copy last message 2025-07-16 06:09:26 -05:00
Robin Moser f45deb37f0 fix: don't sign snapshot commits (#1046) 2025-07-16 04:46:32 -05:00
Matias Insaurralde e89972a396 perf: move ANSI regex compilations to package level (#1040)
Signed-off-by: Matías Insaurralde <matias@insaurral.de>
2025-07-16 04:20:25 -05:00
Frank c3c647a21a wip: github actions 2025-07-16 16:20:06 +08:00
Frank b79167ce66 sync 2025-07-16 16:12:31 +08:00
Frank 7ac0a2bc65 wip: github actions 2025-07-16 16:05:51 +08:00
Frank cb032cff2b wip: github actions 2025-07-16 03:57:14 -04:00
Frank 867a69a751 wip: github actions 2025-07-16 03:54:20 -04:00
Frank 20b8efcc50 wip: github actions 2025-07-16 15:36:23 +08:00
Frank a86d42149f wip: github actions 2025-07-16 14:59:53 +08:00
Frank 82a36acfe3 wip: github action 2025-07-16 14:59:53 +08:00
Dax Raad 0793c3f2a3 clean up export command
publish / publish (push) Has been cancelled
2025-07-15 21:50:43 -04:00
Dax Raad 5c860b0d69 fix share page v1 message 2025-07-15 21:35:32 -04:00
Dax Raad 05bb127a8e enable bash tool in plan mode 2025-07-15 21:28:03 -04:00
aron 1bbd84008f move spoof prompt to support anthropic with custom modes (#1031)
publish / publish (push) Has been cancelled
2025-07-15 21:16:27 -04:00
Stephen MurrayandDax Raad fdfd4d69d3 add support for modified gemini-cli system prompt (#1033)
Co-authored-by: Dax Raad <d@ironbay.co>
2025-07-15 21:13:11 -04:00
Jay 7f659cce36 docs: Update README.md 2025-07-15 20:09:26 -04:00
Jay V 48fcaa83be docs: fix config 2025-07-15 19:54:51 -04:00
Jay V 70c16c4c95 docs: adding action to notify discord 2025-07-15 19:49:38 -04:00
Jay V c1e1ef6eb5 docs: readme 2025-07-15 18:32:04 -04:00
Jay V bb155db8b2 docs: share tweak copy button 2025-07-15 18:25:25 -04:00
John Henry RuddenandJay 7c91f668d1 docs: share add copy button to messages in web interface (#902)
Co-authored-by: Jay <air@live.ca>
2025-07-15 17:56:33 -04:00
Jay V 1af103d29e docs: share handle non bundled langs 2025-07-15 17:47:22 -04:00
Jay V 8a3e581edc docs: share fix diff bugs 2025-07-15 17:47:22 -04:00
Jay V 749e7838a4 docs: share page task tool 2025-07-15 17:47:22 -04:00
Dax Raad 73b46c2bf9 docs: document base URL 2025-07-15 14:57:50 -04:00
Joe Schmittandopencode 8bd250fb15 feat(tui): add /export command to export conversation to editor (#989)
Co-authored-by: opencode <noreply@opencode.ai>
2025-07-15 13:53:21 -05:00
61 changed files with 1915 additions and 1169 deletions
+14
View File
@@ -0,0 +1,14 @@
name: discord
on:
release:
types: [published] # fires only when a release is published
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Send nicely-formatted embed to Discord
uses: SethCohen/github-releases-to-discord@v1
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
+1 -2
View File
@@ -17,8 +17,7 @@ jobs:
fetch-depth: 1 fetch-depth: 1
- name: Run opencode - name: Run opencode
uses: sst/opencode/sdks/github@dev uses: sst/opencode/sdks/github@github-v1
#uses: ./github-actions
env: env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
with: with:
@@ -0,0 +1,29 @@
name: publish-github-action
on:
workflow_dispatch:
concurrency: ${{ github.workflow }}-${{ github.ref }}
permissions:
contents: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- run: git fetch --force --tags
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.2.17
- name: Publish
run: |
git config --global user.email "opencode@sst.dev"
git config --global user.name "opencode"
./scripts/publish-github-action.ts
+13 -11
View File
@@ -30,7 +30,8 @@ brew install sst/tap/opencode # macOS
paru -S opencode-bin # Arch Linux paru -S opencode-bin # Arch Linux
``` ```
> **Note:** Remove versions older than 0.1.x before installing > [!TIP]
> Remove versions older than 0.1.x before installing.
### Documentation ### Documentation
@@ -38,24 +39,25 @@ For more info on how to configure opencode [**head over to our docs**](https://o
### Contributing ### Contributing
WE DO NOT ACCEPT PRs FOR CORE FEATURES
opencode is an opinionated tool so any fundamental feature needs to go through a opencode is an opinionated tool so any fundamental feature needs to go through a
design process with the core team. design process with the core team.
> [!IMPORTANT]
> We do not accept PRs for core features.
However we still merge a ton of PRs - you can contribute: However we still merge a ton of PRs - you can contribute:
- bug fixes - Bug fixes
- improvements to LLM performance - Improvements to LLM performance
- support for new providers - Support for new providers
- fixes for env specific quirks - Fixes for env specific quirks
- missing standard behavior - Missing standard behavior
- documentation - Documentation
Take a look at the git history to see what kind of PRs we end up merging. Take a look at the git history to see what kind of PRs we end up merging.
> **Note**: If you do not follow the above guidelines we might close your PR > [!NOTE]
> that you worked really hard on. > If you do not follow the above guidelines we might close your PR.
To run opencode locally you need. To run opencode locally you need.
+1
View File
@@ -17,3 +17,4 @@
| 2025-07-13 | 50,803 (+1,501) | 86,394 (+4,217) | 137,197 (+5,718) | | 2025-07-13 | 50,803 (+1,501) | 86,394 (+4,217) | 137,197 (+5,718) |
| 2025-07-14 | 53,283 (+2,480) | 87,860 (+1,466) | 141,143 (+3,946) | | 2025-07-14 | 53,283 (+2,480) | 87,860 (+1,466) | 141,143 (+3,946) |
| 2025-07-15 | 57,590 (+4,307) | 91,036 (+3,176) | 148,626 (+7,483) | | 2025-07-15 | 57,590 (+4,307) | 91,036 (+3,176) | 148,626 (+7,483) |
| 2025-07-16 | 62,313 (+4,723) | 95,258 (+4,222) | 157,571 (+8,945) |
+154 -149
View File
@@ -30,6 +30,7 @@
}, },
"dependencies": { "dependencies": {
"@clack/prompts": "0.11.0", "@clack/prompts": "0.11.0",
"@hono/zod-validator": "0.4.2",
"@modelcontextprotocol/sdk": "1.15.1", "@modelcontextprotocol/sdk": "1.15.1",
"@openauthjs/openauth": "0.4.3", "@openauthjs/openauth": "0.4.3",
"ai": "catalog:", "ai": "catalog:",
@@ -45,6 +46,7 @@
"xdg-basedir": "5.1.0", "xdg-basedir": "5.1.0",
"yargs": "18.0.0", "yargs": "18.0.0",
"zod": "catalog:", "zod": "catalog:",
"zod-openapi": "4.1.0",
}, },
"devDependencies": { "devDependencies": {
"@ai-sdk/amazon-bedrock": "2.2.10", "@ai-sdk/amazon-bedrock": "2.2.10",
@@ -79,6 +81,7 @@
"marked": "15.0.12", "marked": "15.0.12",
"marked-shiki": "1.2.0", "marked-shiki": "1.2.0",
"rehype-autolink-headings": "7.1.0", "rehype-autolink-headings": "7.1.0",
"remeda": "2.26.0",
"sharp": "0.32.5", "sharp": "0.32.5",
"shiki": "3.4.2", "shiki": "3.4.2",
"solid-js": "1.9.7", "solid-js": "1.9.7",
@@ -116,9 +119,9 @@
"@apidevtools/json-schema-ref-parser": ["@apidevtools/json-schema-ref-parser@11.9.3", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0" } }, "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ=="], "@apidevtools/json-schema-ref-parser": ["@apidevtools/json-schema-ref-parser@11.9.3", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0" } }, "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ=="],
"@astrojs/cloudflare": ["@astrojs/cloudflare@12.5.4", "", { "dependencies": { "@astrojs/internal-helpers": "0.6.1", "@astrojs/underscore-redirects": "0.6.1", "@cloudflare/workers-types": "^4.20250507.0", "tinyglobby": "^0.2.13", "vite": "^6.3.5", "wrangler": "^4.14.1" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-WKUeMP2tIbddEu0tlVEPj8o9m/8CJB6who3a3jupuIyR56ltmW924ZOMYtp/C9uxH7KeDJXrMszRj3LHs9U97w=="], "@astrojs/cloudflare": ["@astrojs/cloudflare@12.6.0", "", { "dependencies": { "@astrojs/internal-helpers": "0.6.1", "@astrojs/underscore-redirects": "1.0.0", "@cloudflare/workers-types": "^4.20250507.0", "tinyglobby": "^0.2.13", "vite": "^6.3.5", "wrangler": "^4.14.1" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-pQ8bokC59GEiXvyXpC4swBNoL7C/EknP+82KFzQwgR/Aeo5N1oPiAoPHgJbpPya/YF4E26WODdCQfBQDvLRfuw=="],
"@astrojs/compiler": ["@astrojs/compiler@2.12.0", "", {}, "sha512-7bCjW6tVDpUurQLeKBUN9tZ5kSv5qYrGmcn0sG0IwacL7isR2ZbyyA3AdZ4uxsuUFOS2SlgReTH7wkxO6zpqWA=="], "@astrojs/compiler": ["@astrojs/compiler@2.12.2", "", {}, "sha512-w2zfvhjNCkNMmMMOn5b0J8+OmUaBL1o40ipMvqcG6NRpdC+lKxmTi48DT8Xw0SzJ3AfmeFLB45zXZXtmbsjcgw=="],
"@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="], "@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="],
@@ -128,7 +131,7 @@
"@astrojs/prism": ["@astrojs/prism@3.2.0", "", { "dependencies": { "prismjs": "^1.29.0" } }, "sha512-GilTHKGCW6HMq7y3BUv9Ac7GMe/MO9gi9GW62GzKtth0SwukCu/qp2wLiGpEujhY+VVhaG9v7kv/5vFzvf4NYw=="], "@astrojs/prism": ["@astrojs/prism@3.2.0", "", { "dependencies": { "prismjs": "^1.29.0" } }, "sha512-GilTHKGCW6HMq7y3BUv9Ac7GMe/MO9gi9GW62GzKtth0SwukCu/qp2wLiGpEujhY+VVhaG9v7kv/5vFzvf4NYw=="],
"@astrojs/sitemap": ["@astrojs/sitemap@3.4.0", "", { "dependencies": { "sitemap": "^8.0.0", "stream-replace-string": "^2.0.0", "zod": "^3.24.2" } }, "sha512-C5m/xsKvRSILKM3hy47n5wKtTQtJXn8epoYuUmCCstaE9XBt20yInym3Bz2uNbEiNfv11bokoW0MqeXPIvjFIQ=="], "@astrojs/sitemap": ["@astrojs/sitemap@3.4.1", "", { "dependencies": { "sitemap": "^8.0.0", "stream-replace-string": "^2.0.0", "zod": "^3.24.2" } }, "sha512-VjZvr1e4FH6NHyyHXOiQgLiw94LnCVY4v06wN/D0gZKchTMkg71GrAHJz81/huafcmavtLkIv26HnpfDq6/h/Q=="],
"@astrojs/solid-js": ["@astrojs/solid-js@5.1.0", "", { "dependencies": { "vite": "^6.3.5", "vite-plugin-solid": "^2.11.6" }, "peerDependencies": { "solid-devtools": "^0.30.1", "solid-js": "^1.8.5" }, "optionalPeers": ["solid-devtools"] }, "sha512-VmPHOU9k7m6HHCT2Y1mNzifilUnttlowBM36frGcfj5wERJE9Ci0QtWJbzdf6AlcoIirb7xVw+ByupU011Di9w=="], "@astrojs/solid-js": ["@astrojs/solid-js@5.1.0", "", { "dependencies": { "vite": "^6.3.5", "vite-plugin-solid": "^2.11.6" }, "peerDependencies": { "solid-devtools": "^0.30.1", "solid-js": "^1.8.5" }, "optionalPeers": ["solid-devtools"] }, "sha512-VmPHOU9k7m6HHCT2Y1mNzifilUnttlowBM36frGcfj5wERJE9Ci0QtWJbzdf6AlcoIirb7xVw+ByupU011Di9w=="],
@@ -136,24 +139,26 @@
"@astrojs/telemetry": ["@astrojs/telemetry@3.2.1", "", { "dependencies": { "ci-info": "^4.2.0", "debug": "^4.4.0", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^3.0.0", "is-wsl": "^3.1.0", "which-pm-runs": "^1.1.0" } }, "sha512-SSVM820Jqc6wjsn7qYfV9qfeQvePtVc1nSofhyap7l0/iakUKywj3hfy3UJAOV4sGV4Q/u450RD4AaCaFvNPlg=="], "@astrojs/telemetry": ["@astrojs/telemetry@3.2.1", "", { "dependencies": { "ci-info": "^4.2.0", "debug": "^4.4.0", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^3.0.0", "is-wsl": "^3.1.0", "which-pm-runs": "^1.1.0" } }, "sha512-SSVM820Jqc6wjsn7qYfV9qfeQvePtVc1nSofhyap7l0/iakUKywj3hfy3UJAOV4sGV4Q/u450RD4AaCaFvNPlg=="],
"@astrojs/underscore-redirects": ["@astrojs/underscore-redirects@0.6.1", "", {}, "sha512-4bMLrs2KW+8/vHEE5Ffv2HbxCbbgXO+2N6MpoCsMXUlUoi7pgEEx8kbkzMXJ2dZtWF3gvwm9lvgjnFeanC2LGg=="], "@astrojs/underscore-redirects": ["@astrojs/underscore-redirects@1.0.0", "", {}, "sha512-qZxHwVnmb5FXuvRsaIGaqWgnftjCuMY+GSbaVZdBmE4j8AfgPqKPxYp8SUERyJcjpKCEmO4wD6ybuGH8A2kVRQ=="],
"@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="], "@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="],
"@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="],
"@aws-sdk/types": ["@aws-sdk/types@3.821.0", "", { "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" } }, "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA=="], "@aws-sdk/types": ["@aws-sdk/types@3.840.0", "", { "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" } }, "sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA=="],
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
"@babel/compat-data": ["@babel/compat-data@7.27.3", "", {}, "sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw=="], "@babel/compat-data": ["@babel/compat-data@7.28.0", "", {}, "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw=="],
"@babel/core": ["@babel/core@7.27.4", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.4", "@babel/parser": "^7.27.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.27.4", "@babel/types": "^7.27.3", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g=="], "@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="],
"@babel/generator": ["@babel/generator@7.27.3", "", { "dependencies": { "@babel/parser": "^7.27.3", "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q=="], "@babel/generator": ["@babel/generator@7.28.0", "", { "dependencies": { "@babel/parser": "^7.28.0", "@babel/types": "^7.28.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg=="],
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
"@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.27.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.27.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg=="], "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.27.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.27.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg=="],
@@ -166,19 +171,19 @@
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
"@babel/helpers": ["@babel/helpers@7.27.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.27.3" } }, "sha512-Y+bO6U+I7ZKaM5G5rDUZiYfUvQPUibYmAFe7EnKdnKBbVXDZxvp+MWOH5gYciY0EPk4EScsuFMQBbEfpdRKSCQ=="], "@babel/helpers": ["@babel/helpers@7.27.6", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.27.6" } }, "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug=="],
"@babel/parser": ["@babel/parser@7.27.4", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-BRmLHGwpUqLFR2jzx9orBuX/ABDkj2jLKOXrHDTN2aOKL+jFDDKaRNo9nyYsIl9h/UE/7lMKdDjKQQyxKKDZ7g=="], "@babel/parser": ["@babel/parser@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.0" }, "bin": "./bin/babel-parser.js" }, "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g=="],
"@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="], "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="],
"@babel/runtime": ["@babel/runtime@7.27.4", "", {}, "sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA=="], "@babel/runtime": ["@babel/runtime@7.27.6", "", {}, "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q=="],
"@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
"@babel/traverse": ["@babel/traverse@7.27.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.3", "@babel/parser": "^7.27.4", "@babel/template": "^7.27.2", "@babel/types": "^7.27.3", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA=="], "@babel/traverse": ["@babel/traverse@7.28.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/types": "^7.28.0", "debug": "^4.3.1" } }, "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg=="],
"@babel/types": ["@babel/types@7.27.3", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw=="], "@babel/types": ["@babel/types@7.28.1", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ=="],
"@capsizecss/unpack": ["@capsizecss/unpack@2.4.0", "", { "dependencies": { "blob-to-buffer": "^1.2.8", "cross-fetch": "^3.0.4", "fontkit": "^2.0.2" } }, "sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q=="], "@capsizecss/unpack": ["@capsizecss/unpack@2.4.0", "", { "dependencies": { "blob-to-buffer": "^1.2.8", "cross-fetch": "^3.0.4", "fontkit": "^2.0.2" } }, "sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q=="],
@@ -188,17 +193,17 @@
"@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="], "@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.3.2", "", { "peerDependencies": { "unenv": "2.0.0-rc.17", "workerd": "^1.20250508.0" }, "optionalPeers": ["workerd"] }, "sha512-MtUgNl+QkQyhQvv5bbWP+BpBC1N0me4CHHuP2H4ktmOMKdB/6kkz/lo+zqiA4mEazb4y+1cwyNjVrQ2DWeE4mg=="], "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.3.3", "", { "peerDependencies": { "unenv": "2.0.0-rc.17", "workerd": "^1.20250508.0" }, "optionalPeers": ["workerd"] }, "sha512-/M3MEcj3V2WHIRSW1eAQBPRJ6JnGQHc6JKMAPLkDb7pLs3m6X9ES/+K3ceGqxI6TKeF32AWAi7ls0AYzVxCP0A=="],
"@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250525.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-L5l+7sSJJT2+riR5rS3Q3PKNNySPjWfRIeaNGMVRi1dPO6QPi4lwuxfRUFNoeUdilZJUVPfSZvTtj9RedsKznQ=="], "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250709.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-VqwcvnbI8FNCP87ZWNHA3/sAC5U9wMbNnjBG0sHEYzM7B9RPHKYHdVKdBEWhzZXnkQYMK81IHm4CZsK16XxAuQ=="],
"@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250525.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y3IbIdrF/vJWh/WBvshwcSyUh175VAiLRW7963S1dXChrZ1N5wuKGQm9xY69cIGVtitpMJWWW3jLq7J/Xxwm0Q=="], "@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250709.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-A54ttSgXMM4huChPTThhkieOjpDxR+srVOO9zjTHVIyoQxA8zVsku4CcY/GQ95RczMV+yCKVVu/tAME7vwBFuA=="],
"@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250525.0", "", { "os": "linux", "cpu": "x64" }, "sha512-KSyQPAby+c6cpENoO0ayCQlY6QIh28l/+QID7VC1SLXfiNHy+hPNsH1vVBTST6CilHVAQSsy9tCZ9O9XECB8yg=="], "@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250709.0", "", { "os": "linux", "cpu": "x64" }, "sha512-no4O3OK+VXINIxv99OHJDpIgML2ZssrSvImwLtULzqm+cl4t1PIfXNRUqj89ujTkmad+L9y4G6dBQMPCLnmlGg=="],
"@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250525.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Nt0FUxS2kQhJUea4hMCNPaetkrAFDhPnNX/ntwcqVlGgnGt75iaAhupWJbU0GB+gIWlKeuClUUnDZqKbicoKyg=="], "@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250709.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-7cNICk2Qd+m4QGrcmWyAuZJXTHt1ud6isA+dic7Yk42WZmwXhlcUATyvFD9FSQNFcldjuRB4n8JlWEFqZBn+lw=="],
"@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250525.0", "", { "os": "win32", "cpu": "x64" }, "sha512-mwTj+9f3uIa4NEXR1cOa82PjLa6dbrb3J+KCVJFYIaq7e63VxEzOchCXS4tublT2pmOhmFqkgBMXrxozxNkR2Q=="], "@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250709.0", "", { "os": "win32", "cpu": "x64" }, "sha512-j1AyO8V/62Q23EJplWgzBlRCqo/diXgox58AbDqSqgyzCBAlvUzXQRDBab/FPNG/erRqt7I1zQhahrBhrM0uLA=="],
"@cloudflare/workers-types": ["@cloudflare/workers-types@4.20250522.0", "", {}, "sha512-9RIffHobc35JWeddzBguGgPa4wLDr5x5F94+0/qy7LiV6pTBQ/M5qGEN9VA16IDT3EUpYI0WKh6VpcmeVEtVtw=="], "@cloudflare/workers-types": ["@cloudflare/workers-types@4.20250522.0", "", {}, "sha512-9RIffHobc35JWeddzBguGgPa4wLDr5x5F94+0/qy7LiV6pTBQ/M5qGEN9VA16IDT3EUpYI0WKh6VpcmeVEtVtw=="],
@@ -206,71 +211,73 @@
"@ctrl/tinycolor": ["@ctrl/tinycolor@4.1.0", "", {}, "sha512-WyOx8cJQ+FQus4Mm4uPIZA64gbk3Wxh0so5Lcii0aJifqwoVOlfFtorjLE0Hen4OYyHZMXDWqMmaQemBhgxFRQ=="], "@ctrl/tinycolor": ["@ctrl/tinycolor@4.1.0", "", {}, "sha512-WyOx8cJQ+FQus4Mm4uPIZA64gbk3Wxh0so5Lcii0aJifqwoVOlfFtorjLE0Hen4OYyHZMXDWqMmaQemBhgxFRQ=="],
"@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="], "@emnapi/runtime": ["@emnapi/runtime@1.4.4", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.6", "", { "os": "aix", "cpu": "ppc64" }, "sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.5", "", { "os": "android", "cpu": "arm" }, "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA=="], "@esbuild/android-arm": ["@esbuild/android-arm@0.25.6", "", { "os": "android", "cpu": "arm" }, "sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.5", "", { "os": "android", "cpu": "arm64" }, "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg=="], "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.6", "", { "os": "android", "cpu": "arm64" }, "sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.5", "", { "os": "android", "cpu": "x64" }, "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw=="], "@esbuild/android-x64": ["@esbuild/android-x64@0.25.6", "", { "os": "android", "cpu": "x64" }, "sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ=="], "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ=="], "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw=="], "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.6", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw=="], "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.6", "", { "os": "freebsd", "cpu": "x64" }, "sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.5", "", { "os": "linux", "cpu": "arm" }, "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw=="], "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.6", "", { "os": "linux", "cpu": "arm" }, "sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg=="], "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA=="], "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.6", "", { "os": "linux", "cpu": "ia32" }, "sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg=="], "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.6", "", { "os": "linux", "cpu": "none" }, "sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg=="], "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.6", "", { "os": "linux", "cpu": "none" }, "sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ=="], "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.6", "", { "os": "linux", "cpu": "ppc64" }, "sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA=="], "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.6", "", { "os": "linux", "cpu": "none" }, "sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ=="], "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.6", "", { "os": "linux", "cpu": "s390x" }, "sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.5", "", { "os": "linux", "cpu": "x64" }, "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw=="], "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.6", "", { "os": "linux", "cpu": "x64" }, "sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.5", "", { "os": "none", "cpu": "arm64" }, "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw=="], "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.6", "", { "os": "none", "cpu": "arm64" }, "sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.5", "", { "os": "none", "cpu": "x64" }, "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ=="], "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.6", "", { "os": "none", "cpu": "x64" }, "sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.5", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw=="], "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.6", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg=="], "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.6", "", { "os": "openbsd", "cpu": "x64" }, "sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA=="], "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.6", "", { "os": "none", "cpu": "arm64" }, "sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw=="], "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.6", "", { "os": "sunos", "cpu": "x64" }, "sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ=="], "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.5", "", { "os": "win32", "cpu": "x64" }, "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g=="], "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.6", "", { "os": "win32", "cpu": "ia32" }, "sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ=="],
"@expressive-code/core": ["@expressive-code/core@0.41.2", "", { "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-AJW5Tp9czbLqKMzwudL9Rv4js9afXBxkSGLmCNPq1iRgAYcx9NkTPJiSNCesjKRWoVC328AdSu6fqrD22zDgDg=="], "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.6", "", { "os": "win32", "cpu": "x64" }, "sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA=="],
"@expressive-code/plugin-frames": ["@expressive-code/plugin-frames@0.41.2", "", { "dependencies": { "@expressive-code/core": "^0.41.2" } }, "sha512-pfy0hkJI4nbaONjmksFDcuHmIuyPTFmi1JpABe4q2ajskiJtfBf+WDAL2pg595R9JNoPrrH5+aT9lbkx2noicw=="], "@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=="],
"@expressive-code/plugin-shiki": ["@expressive-code/plugin-shiki@0.41.2", "", { "dependencies": { "@expressive-code/core": "^0.41.2", "shiki": "^3.2.2" } }, "sha512-xD4zwqAkDccXqye+235BH5bN038jYiSMLfUrCOmMlzxPDGWdxJDk5z4uUB/aLfivEF2tXyO2zyaarL3Oqht0fQ=="], "@expressive-code/plugin-frames": ["@expressive-code/plugin-frames@0.41.3", "", { "dependencies": { "@expressive-code/core": "^0.41.3" } }, "sha512-rFQtmf/3N2CK3Cq/uERweMTYZnBu+CwxBdHuOftEmfA9iBE7gTVvwpbh82P9ZxkPLvc40UMhYt7uNuAZexycRQ=="],
"@expressive-code/plugin-text-markers": ["@expressive-code/plugin-text-markers@0.41.2", "", { "dependencies": { "@expressive-code/core": "^0.41.2" } }, "sha512-JFWBz2qYxxJOJkkWf96LpeolbnOqJY95TvwYc0hXIHf9oSWV0h0SY268w/5N3EtQaD9KktzDE+VIVwb9jdb3nw=="], "@expressive-code/plugin-shiki": ["@expressive-code/plugin-shiki@0.41.3", "", { "dependencies": { "@expressive-code/core": "^0.41.3", "shiki": "^3.2.2" } }, "sha512-RlTARoopzhFJIOVHLGvuXJ8DCEme/hjV+ZnRJBIxzxsKVpGPW4Oshqg9xGhWTYdHstTsxO663s0cdBLzZj9TQA=="],
"@expressive-code/plugin-text-markers": ["@expressive-code/plugin-text-markers@0.41.3", "", { "dependencies": { "@expressive-code/core": "^0.41.3" } }, "sha512-SN8tkIzDpA0HLAscEYD2IVrfLiid6qEdE9QLlGVSxO1KEw7qYvjpbNBQjUjMr5/jvTJ7ys6zysU2vLPHE0sb2g=="],
"@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="], "@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="],
"@fontsource/ibm-plex-mono": ["@fontsource/ibm-plex-mono@5.2.5", "", {}, "sha512-G09N3GfuT9qj3Ax2FDZvKqZttzM3v+cco2l8uXamhKyXLdmlaUDH5o88/C3vtTHj2oT7yRKsvxz9F+BXbWKMYA=="], "@fontsource/ibm-plex-mono": ["@fontsource/ibm-plex-mono@5.2.5", "", {}, "sha512-G09N3GfuT9qj3Ax2FDZvKqZttzM3v+cco2l8uXamhKyXLdmlaUDH5o88/C3vtTHj2oT7yRKsvxz9F+BXbWKMYA=="],
"@hono/zod-validator": ["@hono/zod-validator@0.5.0", "", { "peerDependencies": { "hono": ">=3.9.0", "zod": "^3.19.1" } }, "sha512-ds5bW6DCgAnNHP33E3ieSbaZFd5dkV52ZjyaXtGoR06APFrCtzAsKZxTHwOrJNBdXsi0e5wNwo5L4nVEVnJUdg=="], "@hono/zod-validator": ["@hono/zod-validator@0.4.2", "", { "peerDependencies": { "hono": ">=3.9.0", "zod": "^3.19.1" } }, "sha512-1rrlBg+EpDPhzOV4hT9pxr5+xDVmKuz6YJl+la7VCwK6ass5ldyKm5fD+umJdV2zhHD6jROoCCv8NbTwyfhT0g=="],
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="], "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="],
@@ -310,13 +317,11 @@
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="], "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg=="],
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
"@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.4", "", {}, "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="],
@@ -394,47 +399,53 @@
"@pagefind/windows-x64": ["@pagefind/windows-x64@1.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-BR1bIRWOMqkf8IoU576YDhij1Wd/Zf2kX/kCI0b2qzCKC8wcc2GQJaaRMCpzvCCrmliO4vtJ6RITp/AnoYUUmQ=="], "@pagefind/windows-x64": ["@pagefind/windows-x64@1.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-BR1bIRWOMqkf8IoU576YDhij1Wd/Zf2kX/kCI0b2qzCKC8wcc2GQJaaRMCpzvCCrmliO4vtJ6RITp/AnoYUUmQ=="],
"@rollup/pluginutils": ["@rollup/pluginutils@5.1.4", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ=="], "@poppinss/colors": ["@poppinss/colors@4.1.5", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.41.1", "", { "os": "android", "cpu": "arm" }, "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw=="], "@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=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.41.1", "", { "os": "android", "cpu": "arm64" }, "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA=="], "@poppinss/exception": ["@poppinss/exception@1.2.2", "", {}, "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.41.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w=="], "@rollup/pluginutils": ["@rollup/pluginutils@5.2.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.41.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg=="], "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.45.0", "", { "os": "android", "cpu": "arm" }, "sha512-2o/FgACbji4tW1dzXOqAV15Eu7DdgbKsF2QKcxfG4xbh5iwU7yr5RRP5/U+0asQliSYv5M4o7BevlGIoSL0LXg=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.41.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg=="], "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.45.0", "", { "os": "android", "cpu": "arm64" }, "sha512-PSZ0SvMOjEAxwZeTx32eI/j5xSYtDCRxGu5k9zvzoY77xUNssZM+WV6HYBLROpY5CkXsbQjvz40fBb7WPwDqtQ=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.41.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA=="], "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.45.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BA4yPIPssPB2aRAWzmqzQ3y2/KotkLyZukVB7j3psK/U3nVJdceo6qr9pLM2xN6iRP/wKfxEbOb1yrlZH6sYZg=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.41.1", "", { "os": "linux", "cpu": "arm" }, "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg=="], "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.45.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Pr2o0lvTwsiG4HCr43Zy9xXrHspyMvsvEw4FwKYqhli4FuLE5FjcZzuQ4cfPe0iUFCvSQG6lACI0xj74FDZKRA=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.41.1", "", { "os": "linux", "cpu": "arm" }, "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA=="], "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.45.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lYE8LkE5h4a/+6VnnLiL14zWMPnx6wNbDG23GcYFpRW1V9hYWHAw9lBZ6ZUIrOaoK7NliF1sdwYGiVmziUF4vA=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.41.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA=="], "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.45.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-PVQWZK9sbzpvqC9Q0GlehNNSVHR+4m7+wET+7FgSnKG3ci5nAMgGmr9mGBXzAuE5SvguCKJ6mHL6vq1JaJ/gvw=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.41.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg=="], "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.45.0", "", { "os": "linux", "cpu": "arm" }, "sha512-hLrmRl53prCcD+YXTfNvXd776HTxNh8wPAMllusQ+amcQmtgo3V5i/nkhPN6FakW+QVLoUUr2AsbtIRPFU3xIA=="],
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.41.1", "", { "os": "linux", "cpu": "none" }, "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw=="], "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.45.0", "", { "os": "linux", "cpu": "arm" }, "sha512-XBKGSYcrkdiRRjl+8XvrUR3AosXU0NvF7VuqMsm7s5nRy+nt58ZMB19Jdp1RdqewLcaYnpk8zeVs/4MlLZEJxw=="],
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.41.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A=="], "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.45.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-fRvZZPUiBz7NztBE/2QnCS5AtqLVhXmUOPj9IHlfGEXkapgImf4W9+FSkL8cWqoAjozyUzqFmSc4zh2ooaeF6g=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.41.1", "", { "os": "linux", "cpu": "none" }, "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw=="], "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.45.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Btv2WRZOcUGi8XU80XwIvzTg4U6+l6D0V6sZTrZx214nrwxw5nAi8hysaXj/mctyClWgesyuxbeLylCBNauimg=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.41.1", "", { "os": "linux", "cpu": "none" }, "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw=="], "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.45.0", "", { "os": "linux", "cpu": "none" }, "sha512-Li0emNnwtUZdLwHjQPBxn4VWztcrw/h7mgLyHiEI5Z0MhpeFGlzaiBHpSNVOMB/xucjXTTcO+dhv469Djr16KA=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.41.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g=="], "@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.45.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-sB8+pfkYx2kvpDCfd63d5ScYT0Fz1LO6jIb2zLZvmK9ob2D8DeVqrmBDE0iDK8KlBVmsTNzrjr3G1xV4eUZhSw=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.41.1", "", { "os": "linux", "cpu": "x64" }, "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A=="], "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.45.0", "", { "os": "linux", "cpu": "none" }, "sha512-5GQ6PFhh7E6jQm70p1aW05G2cap5zMOvO0se5JMecHeAdj5ZhWEHbJ4hiKpfi1nnnEdTauDXxPgXae/mqjow9w=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.41.1", "", { "os": "linux", "cpu": "x64" }, "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ=="], "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.45.0", "", { "os": "linux", "cpu": "none" }, "sha512-N/euLsBd1rekWcuduakTo/dJw6U6sBP3eUq+RXM9RNfPuWTvG2w/WObDkIvJ2KChy6oxZmOSC08Ak2OJA0UiAA=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.41.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ=="], "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.45.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-2l9sA7d7QdikL0xQwNMO3xURBUNEWyHVHfAsHsUdq+E/pgLTUcCE+gih5PCdmyHmfTDeXUWVhqL0WZzg0nua3g=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.41.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg=="], "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.45.0", "", { "os": "linux", "cpu": "x64" }, "sha512-XZdD3fEEQcwG2KrJDdEQu7NrHonPxxaV0/w2HpvINBdcqebz1aL+0vM2WFJq4DeiAVT6F5SUQas65HY5JDqoPw=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.41.1", "", { "os": "win32", "cpu": "x64" }, "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw=="], "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.45.0", "", { "os": "linux", "cpu": "x64" }, "sha512-7ayfgvtmmWgKWBkCGg5+xTQ0r5V1owVm67zTrsEY1008L5ro7mCyGYORomARt/OquB9KY7LpxVBZes+oSniAAQ=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.45.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-B+IJgcBnE2bm93jEW5kHisqvPITs4ddLOROAcOc/diBgrEiQJJ6Qcjby75rFSmH5eMGrqJryUgJDhrfj942apQ=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.45.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-+CXwwG66g0/FpWOnP/v1HnrGVSOygK/osUbu3wPRy8ECXjoYKjRAyfxYpDQOfghC5qPJYLPH0oN4MCOjwgdMug=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.45.0", "", { "os": "win32", "cpu": "x64" }, "sha512-SRf1cytG7wqcHVLrBc9VtPK4pU5wxiB/lNIkNmW2ApKXIg+RpqwHfsaEK+e7eH4A1BpI6BX/aBWXxZCIrJg3uA=="],
"@shikijs/core": ["@shikijs/core@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="], "@shikijs/core": ["@shikijs/core@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="],
@@ -452,6 +463,8 @@
"@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="],
"@sindresorhus/is": ["@sindresorhus/is@7.0.2", "", {}, "sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw=="],
"@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.0.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.3.1", "@smithy/util-hex-encoding": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-7XoWfZqWb/QoR/rAU4VSi0mWnO2vu9/ltS6JZ5ZSZv0eovLVfDfu0/AX4ub33RsJTOth3TiFWSHS5YdztvFnig=="], "@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.0.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.3.1", "@smithy/util-hex-encoding": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-7XoWfZqWb/QoR/rAU4VSi0mWnO2vu9/ltS6JZ5ZSZv0eovLVfDfu0/AX4ub33RsJTOth3TiFWSHS5YdztvFnig=="],
"@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="], "@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
@@ -464,6 +477,8 @@
"@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="], "@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
"@speed-highlight/core": ["@speed-highlight/core@1.2.7", "", {}, "sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g=="],
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
"@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="], "@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="],
@@ -482,7 +497,7 @@
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
"@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="],
@@ -522,7 +537,7 @@
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
"acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
@@ -550,13 +565,11 @@
"array-iterate": ["array-iterate@2.0.1", "", {}, "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg=="], "array-iterate": ["array-iterate@2.0.1", "", {}, "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg=="],
"as-table": ["as-table@1.0.55", "", { "dependencies": { "printable-characters": "^1.0.42" } }, "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ=="],
"astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="],
"astro": ["astro@5.7.13", "", { "dependencies": { "@astrojs/compiler": "^2.11.0", "@astrojs/internal-helpers": "0.6.1", "@astrojs/markdown-remark": "6.3.1", "@astrojs/telemetry": "3.2.1", "@capsizecss/unpack": "^2.4.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.1.4", "acorn": "^8.14.1", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.2.0", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.0.2", "cssesc": "^3.0.0", "debug": "^4.4.0", "deterministic-object-hash": "^2.0.2", "devalue": "^5.1.1", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.6.0", "esbuild": "^0.25.0", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.3.0", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.1.1", "js-yaml": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.17", "magicast": "^0.3.5", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.0", "package-manager-detector": "^1.1.0", "picomatch": "^4.0.2", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.1", "shiki": "^3.2.1", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.12", "tsconfck": "^3.1.5", "ultrahtml": "^1.6.0", "unifont": "~0.5.0", "unist-util-visit": "^5.0.0", "unstorage": "^1.15.0", "vfile": "^6.0.3", "vite": "^6.3.4", "vitefu": "^1.0.6", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.1", "zod": "^3.24.2", "zod-to-json-schema": "^3.24.5", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.33.3" }, "bin": { "astro": "astro.js" } }, "sha512-cRGq2llKOhV3XMcYwQpfBIUcssN6HEK5CRbcMxAfd9OcFhvWE7KUy50zLioAZVVl3AqgUTJoNTlmZfD2eG0G1w=="], "astro": ["astro@5.7.13", "", { "dependencies": { "@astrojs/compiler": "^2.11.0", "@astrojs/internal-helpers": "0.6.1", "@astrojs/markdown-remark": "6.3.1", "@astrojs/telemetry": "3.2.1", "@capsizecss/unpack": "^2.4.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.1.4", "acorn": "^8.14.1", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.2.0", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.0.2", "cssesc": "^3.0.0", "debug": "^4.4.0", "deterministic-object-hash": "^2.0.2", "devalue": "^5.1.1", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.6.0", "esbuild": "^0.25.0", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.3.0", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.1.1", "js-yaml": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.17", "magicast": "^0.3.5", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.0", "package-manager-detector": "^1.1.0", "picomatch": "^4.0.2", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.1", "shiki": "^3.2.1", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.12", "tsconfck": "^3.1.5", "ultrahtml": "^1.6.0", "unifont": "~0.5.0", "unist-util-visit": "^5.0.0", "unstorage": "^1.15.0", "vfile": "^6.0.3", "vite": "^6.3.4", "vitefu": "^1.0.6", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.1", "zod": "^3.24.2", "zod-to-json-schema": "^3.24.5", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.33.3" }, "bin": { "astro": "astro.js" } }, "sha512-cRGq2llKOhV3XMcYwQpfBIUcssN6HEK5CRbcMxAfd9OcFhvWE7KUy50zLioAZVVl3AqgUTJoNTlmZfD2eG0G1w=="],
"astro-expressive-code": ["astro-expressive-code@0.41.2", "", { "dependencies": { "rehype-expressive-code": "^0.41.2" }, "peerDependencies": { "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0" } }, "sha512-HN0jWTnhr7mIV/2e6uu4PPRNNo/k4UEgTLZqbp3MrHU+caCARveG2yZxaZVBmxyiVdYqW5Pd3u3n2zjnshixbw=="], "astro-expressive-code": ["astro-expressive-code@0.41.3", "", { "dependencies": { "rehype-expressive-code": "^0.41.3" }, "peerDependencies": { "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0" } }, "sha512-u+zHMqo/QNLE2eqYRCrK3+XMlKakv33Bzuz+56V1gs8H0y6TZ0hIi3VNbIxeTn51NLn+mJfUV/A0kMNfE4rANw=="],
"async-lock": ["async-lock@1.4.1", "", {}, "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ=="], "async-lock": ["async-lock@1.4.1", "", {}, "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ=="],
@@ -576,9 +589,9 @@
"bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
"bare-events": ["bare-events@2.5.4", "", {}, "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA=="], "bare-events": ["bare-events@2.6.0", "", {}, "sha512-EKZ5BTXYExaNqi3I3f9RtEsaI/xBSGjE0XZCZilPzFAV/goswFHuPd9jEZlPIZ/iNZJwDSao9qRiScySz7MbQg=="],
"bare-fs": ["bare-fs@4.1.5", "", { "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", "bare-stream": "^2.6.4" }, "peerDependencies": { "bare-buffer": "*" }, "optionalPeers": ["bare-buffer"] }, "sha512-1zccWBMypln0jEE05LzZt+V/8y8AQsQQqxtklqaIyg5nu6OAYFhZxPXinJTSG+kU5qyNmeLgcn9AW7eHiCHVLA=="], "bare-fs": ["bare-fs@4.1.6", "", { "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", "bare-stream": "^2.6.4" }, "peerDependencies": { "bare-buffer": "*" }, "optionalPeers": ["bare-buffer"] }, "sha512-25RsLF33BqooOEFNdMcEhMpJy8EoR88zSMrnOQOaM3USnOK2VmaJ1uaQEwPA6AQjrv1lXChScosN6CzbwbO9OQ=="],
"bare-os": ["bare-os@3.6.1", "", {}, "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g=="], "bare-os": ["bare-os@3.6.1", "", {}, "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g=="],
@@ -610,7 +623,7 @@
"brotli": ["brotli@1.3.3", "", { "dependencies": { "base64-js": "^1.1.2" } }, "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg=="], "brotli": ["brotli@1.3.3", "", { "dependencies": { "base64-js": "^1.1.2" } }, "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg=="],
"browserslist": ["browserslist@4.25.0", "", { "dependencies": { "caniuse-lite": "^1.0.30001718", "electron-to-chromium": "^1.5.160", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA=="], "browserslist": ["browserslist@4.25.1", "", { "dependencies": { "caniuse-lite": "^1.0.30001726", "electron-to-chromium": "^1.5.173", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw=="],
"buffer": ["buffer@4.9.2", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" } }, "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg=="], "buffer": ["buffer@4.9.2", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" } }, "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg=="],
@@ -628,7 +641,7 @@
"camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="], "camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="],
"caniuse-lite": ["caniuse-lite@1.0.30001720", "", {}, "sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g=="], "caniuse-lite": ["caniuse-lite@1.0.30001727", "", {}, "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q=="],
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
@@ -646,7 +659,7 @@
"chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="],
"ci-info": ["ci-info@4.2.0", "", {}, "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg=="], "ci-info": ["ci-info@4.3.0", "", {}, "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ=="],
"clean-git-ref": ["clean-git-ref@2.0.1", "", {}, "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw=="], "clean-git-ref": ["clean-git-ref@2.0.1", "", {}, "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw=="],
@@ -694,7 +707,7 @@
"crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="], "crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="],
"css-selector-parser": ["css-selector-parser@3.1.2", "", {}, "sha512-WfUcL99xWDs7b3eZPoRszWVfbNo8ErCF15PTvVROjkShGlAfjIkG6hlfj/sl6/rfo5Q9x9ryJ3VqVnAZDA+gcw=="], "css-selector-parser": ["css-selector-parser@3.1.3", "", {}, "sha512-gJMigczVZqYAk0hPVzx/M4Hm1D9QOtqkdQk9005TNzDIUGzo5cnHEDiKUT7jGPximL/oYb+LIitcHFQ4aKupxg=="],
"css-tree": ["css-tree@3.1.0", "", { "dependencies": { "mdn-data": "2.12.2", "source-map-js": "^1.0.1" } }, "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w=="], "css-tree": ["css-tree@3.1.0", "", { "dependencies": { "mdn-data": "2.12.2", "source-map-js": "^1.0.1" } }, "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w=="],
@@ -702,13 +715,11 @@
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"data-uri-to-buffer": ["data-uri-to-buffer@2.0.2", "", {}, "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA=="],
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
"decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="], "decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="],
"decode-named-character-reference": ["decode-named-character-reference@1.1.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w=="], "decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="],
"decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="],
@@ -754,15 +765,17 @@
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
"electron-to-chromium": ["electron-to-chromium@1.5.161", "", {}, "sha512-hwtetwfKNZo/UlwHIVBlKZVdy7o8bIZxxKs0Mv/ROPiQQQmDgdm5a+KvKtBsxM8ZjFzTaCeLoodZ8jiBE3o9rA=="], "electron-to-chromium": ["electron-to-chromium@1.5.183", "", {}, "sha512-vCrDBYjQCAEefWGjlK3EpoSKfKbT10pR4XXPdn65q7snuNOZnthoVpBfZPykmDapOKfoD+MMIPG8ZjKyyc9oHA=="],
"emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="], "emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
"end-of-stream": ["end-of-stream@1.4.4", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="], "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
"entities": ["entities@6.0.0", "", {}, "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw=="], "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
"error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="],
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
@@ -776,7 +789,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=="], "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.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.5", "@esbuild/android-arm": "0.25.5", "@esbuild/android-arm64": "0.25.5", "@esbuild/android-x64": "0.25.5", "@esbuild/darwin-arm64": "0.25.5", "@esbuild/darwin-x64": "0.25.5", "@esbuild/freebsd-arm64": "0.25.5", "@esbuild/freebsd-x64": "0.25.5", "@esbuild/linux-arm": "0.25.5", "@esbuild/linux-arm64": "0.25.5", "@esbuild/linux-ia32": "0.25.5", "@esbuild/linux-loong64": "0.25.5", "@esbuild/linux-mips64el": "0.25.5", "@esbuild/linux-ppc64": "0.25.5", "@esbuild/linux-riscv64": "0.25.5", "@esbuild/linux-s390x": "0.25.5", "@esbuild/linux-x64": "0.25.5", "@esbuild/netbsd-arm64": "0.25.5", "@esbuild/netbsd-x64": "0.25.5", "@esbuild/openbsd-arm64": "0.25.5", "@esbuild/openbsd-x64": "0.25.5", "@esbuild/sunos-x64": "0.25.5", "@esbuild/win32-arm64": "0.25.5", "@esbuild/win32-ia32": "0.25.5", "@esbuild/win32-x64": "0.25.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ=="], "esbuild": ["esbuild@0.25.6", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.6", "@esbuild/android-arm": "0.25.6", "@esbuild/android-arm64": "0.25.6", "@esbuild/android-x64": "0.25.6", "@esbuild/darwin-arm64": "0.25.6", "@esbuild/darwin-x64": "0.25.6", "@esbuild/freebsd-arm64": "0.25.6", "@esbuild/freebsd-x64": "0.25.6", "@esbuild/linux-arm": "0.25.6", "@esbuild/linux-arm64": "0.25.6", "@esbuild/linux-ia32": "0.25.6", "@esbuild/linux-loong64": "0.25.6", "@esbuild/linux-mips64el": "0.25.6", "@esbuild/linux-ppc64": "0.25.6", "@esbuild/linux-riscv64": "0.25.6", "@esbuild/linux-s390x": "0.25.6", "@esbuild/linux-x64": "0.25.6", "@esbuild/netbsd-arm64": "0.25.6", "@esbuild/netbsd-x64": "0.25.6", "@esbuild/openbsd-arm64": "0.25.6", "@esbuild/openbsd-x64": "0.25.6", "@esbuild/openharmony-arm64": "0.25.6", "@esbuild/sunos-x64": "0.25.6", "@esbuild/win32-arm64": "0.25.6", "@esbuild/win32-ia32": "0.25.6", "@esbuild/win32-x64": "0.25.6" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
@@ -814,11 +827,11 @@
"express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], "express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
"express-rate-limit": ["express-rate-limit@7.5.0", "", { "peerDependencies": { "express": "^4.11 || 5 || ^5.0.0-beta.1" } }, "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg=="], "express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="],
"expressive-code": ["expressive-code@0.41.2", "", { "dependencies": { "@expressive-code/core": "^0.41.2", "@expressive-code/plugin-frames": "^0.41.2", "@expressive-code/plugin-shiki": "^0.41.2", "@expressive-code/plugin-text-markers": "^0.41.2" } }, "sha512-aLZiZaqorRtNExtGpUjK9zFH9aTpWeoTXMyLo4b4IcuXfPqtLPPxhRm/QlPb8QqIcMMXnSiGRHSFpQfX0m7HJw=="], "expressive-code": ["expressive-code@0.41.3", "", { "dependencies": { "@expressive-code/core": "^0.41.3", "@expressive-code/plugin-frames": "^0.41.3", "@expressive-code/plugin-shiki": "^0.41.3", "@expressive-code/plugin-text-markers": "^0.41.3" } }, "sha512-YLnD62jfgBZYrXIPQcJ0a51Afv9h8VlWqEGK9uU2T5nL/5rb8SnA86+7+mgCZe5D34Tff5RNEA5hjNVJYHzrFg=="],
"exsolve": ["exsolve@1.0.5", "", {}, "sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg=="], "exsolve": ["exsolve@1.0.7", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="],
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
@@ -830,7 +843,7 @@
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
"fdir": ["fdir@6.4.5", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw=="], "fdir": ["fdir@6.4.6", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w=="],
"finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="], "finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
@@ -862,16 +875,12 @@
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
"get-source": ["get-source@2.0.12", "", { "dependencies": { "data-uri-to-buffer": "^2.0.0", "source-map": "^0.6.1" } }, "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w=="],
"github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="],
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
"glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="],
"globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
"h3": ["h3@1.15.3", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.4", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.0", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z6GknHqyX0h9aQaTx22VZDf6QyZn+0Nh+Ym8O/u0SGSkyF5cuTJYKlc8MkzW3Nzf9LE1ivcpmYC3FUGpywhuUQ=="], "h3": ["h3@1.15.3", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.4", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.0", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z6GknHqyX0h9aQaTx22VZDf6QyZn+0Nh+Ym8O/u0SGSkyF5cuTJYKlc8MkzW3Nzf9LE1ivcpmYC3FUGpywhuUQ=="],
@@ -1174,7 +1183,7 @@
"mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
"miniflare": ["miniflare@4.20250525.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": "^5.28.5", "workerd": "1.20250525.0", "ws": "8.18.0", "youch": "3.3.4", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-4PJlT5WA+hfclFU5Q7xnpG1G1VGYTXaf/3iu6iKQ8IsbSi9QvPTA2bSZ5goCFxmJXDjV4cxttVxB0Wl1CLuQ0w=="], "miniflare": ["miniflare@4.20250709.0", "", { "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": "^5.28.5", "workerd": "1.20250709.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-dRGXi6Do9ArQZt7205QGWZ1tD6k6xQNY/mAZBAtiaQYvKxFuNyiHYlFnSN8Co4AFCVOozo/U52sVAaHvlcmnew=="],
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
@@ -1186,8 +1195,6 @@
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="],
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="], "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="],
@@ -1206,7 +1213,7 @@
"node-fetch-native": ["node-fetch-native@1.6.6", "", {}, "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ=="], "node-fetch-native": ["node-fetch-native@1.6.6", "", {}, "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ=="],
"node-mock-http": ["node-mock-http@1.0.0", "", {}, "sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ=="], "node-mock-http": ["node-mock-http@1.0.1", "", {}, "sha512-0gJJgENizp4ghds/Ywu2FCmcRsgBTmRQzYPZm61wy+Em2sBarSka0OhQS5huLBg6od1zkNpnWMCZloQDFVvOMQ=="],
"node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="],
@@ -1282,7 +1289,7 @@
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
"postcss": ["postcss@8.5.4", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w=="], "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
"postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="], "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="],
@@ -1292,8 +1299,6 @@
"prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="], "prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="],
"printable-characters": ["printable-characters@1.0.42", "", {}, "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ=="],
"prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="], "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="],
"prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
@@ -1302,7 +1307,7 @@
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
"pump": ["pump@3.0.2", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw=="], "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="],
"punycode": ["punycode@1.3.2", "", {}, "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw=="], "punycode": ["punycode@1.3.2", "", {}, "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw=="],
@@ -1340,7 +1345,7 @@
"rehype-autolink-headings": ["rehype-autolink-headings@7.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "hast-util-heading-rank": "^3.0.0", "hast-util-is-element": "^3.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw=="], "rehype-autolink-headings": ["rehype-autolink-headings@7.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "hast-util-heading-rank": "^3.0.0", "hast-util-is-element": "^3.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw=="],
"rehype-expressive-code": ["rehype-expressive-code@0.41.2", "", { "dependencies": { "expressive-code": "^0.41.2" } }, "sha512-vHYfWO9WxAw6kHHctddOt+P4266BtyT1mrOIuxJD+1ELuvuJAa5uBIhYt0OVMyOhlvf57hzWOXJkHnMhpaHyxw=="], "rehype-expressive-code": ["rehype-expressive-code@0.41.3", "", { "dependencies": { "expressive-code": "^0.41.3" } }, "sha512-8d9Py4c/V6I/Od2VIXFAdpiO2kc0SV2qTJsRAaqSIcM9aruW4ASLNe2kOEo1inXAAkIhpFzAHTc358HKbvpNUg=="],
"rehype-format": ["rehype-format@5.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-format": "^1.0.0" } }, "sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ=="], "rehype-format": ["rehype-format@5.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-format": "^1.0.0" } }, "sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ=="],
@@ -1366,7 +1371,7 @@
"remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="], "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="],
"remeda": ["remeda@2.22.3", "", { "dependencies": { "type-fest": "^4.40.1" } }, "sha512-Ka6965m9Zu9OLsysWxVf3jdJKmp6+PKzDv7HWHinEevf0JOJ9y02YpjiC/sKxRpCqGhVyvm1U+0YIj+E6DMgKw=="], "remeda": ["remeda@2.26.0", "", { "dependencies": { "type-fest": "^4.41.0" } }, "sha512-lmNNwtaC6Co4m0WTTNoZ/JlpjEqAjPZO0+czC9YVRQUpkbS4x8Hmh+Mn9HPfJfiXqUQ5IXXgSXSOB2pBKAytdA=="],
"restructure": ["restructure@3.0.2", "", {}, "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw=="], "restructure": ["restructure@3.0.2", "", {}, "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw=="],
@@ -1378,7 +1383,7 @@
"retext-stringify": ["retext-stringify@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unified": "^11.0.0" } }, "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA=="], "retext-stringify": ["retext-stringify@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unified": "^11.0.0" } }, "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA=="],
"rollup": ["rollup@4.41.1", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.41.1", "@rollup/rollup-android-arm64": "4.41.1", "@rollup/rollup-darwin-arm64": "4.41.1", "@rollup/rollup-darwin-x64": "4.41.1", "@rollup/rollup-freebsd-arm64": "4.41.1", "@rollup/rollup-freebsd-x64": "4.41.1", "@rollup/rollup-linux-arm-gnueabihf": "4.41.1", "@rollup/rollup-linux-arm-musleabihf": "4.41.1", "@rollup/rollup-linux-arm64-gnu": "4.41.1", "@rollup/rollup-linux-arm64-musl": "4.41.1", "@rollup/rollup-linux-loongarch64-gnu": "4.41.1", "@rollup/rollup-linux-powerpc64le-gnu": "4.41.1", "@rollup/rollup-linux-riscv64-gnu": "4.41.1", "@rollup/rollup-linux-riscv64-musl": "4.41.1", "@rollup/rollup-linux-s390x-gnu": "4.41.1", "@rollup/rollup-linux-x64-gnu": "4.41.1", "@rollup/rollup-linux-x64-musl": "4.41.1", "@rollup/rollup-win32-arm64-msvc": "4.41.1", "@rollup/rollup-win32-ia32-msvc": "4.41.1", "@rollup/rollup-win32-x64-msvc": "4.41.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw=="], "rollup": ["rollup@4.45.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.45.0", "@rollup/rollup-android-arm64": "4.45.0", "@rollup/rollup-darwin-arm64": "4.45.0", "@rollup/rollup-darwin-x64": "4.45.0", "@rollup/rollup-freebsd-arm64": "4.45.0", "@rollup/rollup-freebsd-x64": "4.45.0", "@rollup/rollup-linux-arm-gnueabihf": "4.45.0", "@rollup/rollup-linux-arm-musleabihf": "4.45.0", "@rollup/rollup-linux-arm64-gnu": "4.45.0", "@rollup/rollup-linux-arm64-musl": "4.45.0", "@rollup/rollup-linux-loongarch64-gnu": "4.45.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.45.0", "@rollup/rollup-linux-riscv64-gnu": "4.45.0", "@rollup/rollup-linux-riscv64-musl": "4.45.0", "@rollup/rollup-linux-s390x-gnu": "4.45.0", "@rollup/rollup-linux-x64-gnu": "4.45.0", "@rollup/rollup-linux-x64-musl": "4.45.0", "@rollup/rollup-win32-arm64-msvc": "4.45.0", "@rollup/rollup-win32-ia32-msvc": "4.45.0", "@rollup/rollup-win32-x64-msvc": "4.45.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-WLjEcJRIo7i3WDDgOIJqVI2d+lAC3EwvOGy+Xfq6hs+GQuAA4Di/H72xmXkOhrIWFg2PFYSKZYfH0f4vfKXN4A=="],
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
@@ -1408,7 +1413,7 @@
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
"sha.js": ["sha.js@2.4.11", "", { "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" }, "bin": { "sha.js": "./bin.js" } }, "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ=="], "sha.js": ["sha.js@2.4.12", "", { "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1", "to-buffer": "^1.2.0" }, "bin": { "sha.js": "bin.js" } }, "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w=="],
"sharp": ["sharp@0.32.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.2", "node-addon-api": "^6.1.0", "prebuild-install": "^7.1.1", "semver": "^7.5.4", "simple-get": "^4.0.1", "tar-fs": "^3.0.4", "tunnel-agent": "^0.6.0" } }, "sha512-0dap3iysgDkNaPOaOL4X/0akdu0ma62GcdC2NBQ+93eqpePdDdr2/LM0sFdDSMmN7yS+odyZtPsb7tx/cYBKnQ=="], "sharp": ["sharp@0.32.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.2", "node-addon-api": "^6.1.0", "prebuild-install": "^7.1.1", "semver": "^7.5.4", "simple-get": "^4.0.1", "tar-fs": "^3.0.4", "tunnel-agent": "^0.6.0" } }, "sha512-0dap3iysgDkNaPOaOL4X/0akdu0ma62GcdC2NBQ+93eqpePdDdr2/LM0sFdDSMmN7yS+odyZtPsb7tx/cYBKnQ=="],
@@ -1436,7 +1441,7 @@
"sitemap": ["sitemap@8.0.0", "", { "dependencies": { "@types/node": "^17.0.5", "@types/sax": "^1.2.1", "arg": "^5.0.0", "sax": "^1.2.4" }, "bin": { "sitemap": "dist/cli.js" } }, "sha512-+AbdxhM9kJsHtruUF39bwS/B0Fytw6Fr1o4ZAIAEqA6cke2xcoO2GleBw9Zw7nRzILVEgz7zBM5GiTJjie1G9A=="], "sitemap": ["sitemap@8.0.0", "", { "dependencies": { "@types/node": "^17.0.5", "@types/sax": "^1.2.1", "arg": "^5.0.0", "sax": "^1.2.4" }, "bin": { "sitemap": "dist/cli.js" } }, "sha512-+AbdxhM9kJsHtruUF39bwS/B0Fytw6Fr1o4ZAIAEqA6cke2xcoO2GleBw9Zw7nRzILVEgz7zBM5GiTJjie1G9A=="],
"smol-toml": ["smol-toml@1.3.4", "", {}, "sha512-UOPtVuYkzYGee0Bd2Szz8d2G3RfMfJ2t3qVdZUAozZyAk+a0Sxa+QKix0YCwjL/A1RR0ar44nCxaoN9FxdJGwA=="], "smol-toml": ["smol-toml@1.4.1", "", {}, "sha512-CxdwHXyYTONGHThDbq5XdwbFsuY4wlClRGejfE2NtwUtiHYsP1QtNsHb/hnj31jKYSchztJsaA8pSQoVzkfCFg=="],
"solid-js": ["solid-js@1.9.7", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-/saTKi8iWEM233n5OSi1YHCCuh66ZIQ7aK2hsToPe4tqGm7qAejU1SwNuTPivbWAYq7SjuHVVYxxuZQNRbICiw=="], "solid-js": ["solid-js@1.9.7", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-/saTKi8iWEM233n5OSi1YHCCuh66ZIQ7aK2hsToPe4tqGm7qAejU1SwNuTPivbWAYq7SjuHVVYxxuZQNRbICiw=="],
@@ -1466,15 +1471,13 @@
"sst-win32-x86": ["sst-win32-x86@3.17.8", "", { "os": "win32", "cpu": "none" }, "sha512-oVmFa/PoElQmfnGJlB0w6rPXiYuldiagO6AbrLMT/6oAnWerLQ8Uhv9tJWfMh3xtPLImQLTjxDo1v0AIzEv9QA=="], "sst-win32-x86": ["sst-win32-x86@3.17.8", "", { "os": "win32", "cpu": "none" }, "sha512-oVmFa/PoElQmfnGJlB0w6rPXiYuldiagO6AbrLMT/6oAnWerLQ8Uhv9tJWfMh3xtPLImQLTjxDo1v0AIzEv9QA=="],
"stacktracey": ["stacktracey@2.1.8", "", { "dependencies": { "as-table": "^1.0.36", "get-source": "^2.0.12" } }, "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw=="], "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
"statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
"stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="], "stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="],
"stream-replace-string": ["stream-replace-string@2.0.0", "", {}, "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w=="], "stream-replace-string": ["stream-replace-string@2.0.0", "", {}, "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w=="],
"streamx": ["streamx@2.22.0", "", { "dependencies": { "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" }, "optionalDependencies": { "bare-events": "^2.2.0" } }, "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw=="], "streamx": ["streamx@2.22.1", "", { "dependencies": { "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" }, "optionalDependencies": { "bare-events": "^2.2.0" } }, "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA=="],
"string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
@@ -1486,11 +1489,13 @@
"strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="],
"style-to-js": ["style-to-js@1.1.16", "", { "dependencies": { "style-to-object": "1.0.8" } }, "sha512-/Q6ld50hKYPH3d/r6nr117TZkHR0w0kGGIVfpG9N6D8NymRPM9RqCUv4pRpJ62E5DqOYx2AFpbZMyCPnjQCnOw=="], "style-to-js": ["style-to-js@1.1.17", "", { "dependencies": { "style-to-object": "1.0.9" } }, "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA=="],
"style-to-object": ["style-to-object@1.0.8", "", { "dependencies": { "inline-style-parser": "0.2.4" } }, "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g=="], "style-to-object": ["style-to-object@1.0.9", "", { "dependencies": { "inline-style-parser": "0.2.4" } }, "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw=="],
"tar-fs": ["tar-fs@3.0.9", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-XF4w9Xp+ZQgifKakjZYmFdkLoSWd34VGKcsTCwlNWM7QG3ZbaxnTsaBwnjFZqHRf/rROxaR8rXnbtwdvaDI+lA=="], "supports-color": ["supports-color@10.0.0", "", {}, "sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ=="],
"tar-fs": ["tar-fs@3.1.0", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-5Mty5y/sOF1YWj1J6GiBodjlDc05CUR8PKXrsnFAiSG0xA+GHeWLovaZPYUDXkH/1iKRf2+M5+OrRgzC7O9b7w=="],
"tar-stream": ["tar-stream@3.1.7", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="], "tar-stream": ["tar-stream@3.1.7", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="],
@@ -1502,6 +1507,8 @@
"tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="], "tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="],
"to-buffer": ["to-buffer@1.2.1", "", { "dependencies": { "isarray": "^2.0.5", "safe-buffer": "^5.2.1", "typed-array-buffer": "^1.0.3" } }, "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ=="],
"toad-cache": ["toad-cache@3.7.0", "", {}, "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw=="], "toad-cache": ["toad-cache@3.7.0", "", {}, "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw=="],
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
@@ -1526,6 +1533,8 @@
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
"typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="],
"typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
"ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="], "ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="],
@@ -1546,7 +1555,7 @@
"unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
"unifont": ["unifont@0.5.0", "", { "dependencies": { "css-tree": "^3.0.0", "ohash": "^2.0.0" } }, "sha512-4DueXMP5Hy4n607sh+vJ+rajoLu778aU3GzqeTCqsD/EaUcvqZT9wPC8kgK6Vjh22ZskrxyRCR71FwNOaYn6jA=="], "unifont": ["unifont@0.5.2", "", { "dependencies": { "css-tree": "^3.0.0", "ofetch": "^1.4.1", "ohash": "^2.0.0" } }, "sha512-LzR4WUqzH9ILFvjLAUU7dK3Lnou/qd5kD+IakBtBK4S15/+x2y9VX+DcWQv6s551R6W+vzwgVS6tFg3XggGBgg=="],
"unist-util-find-after": ["unist-util-find-after@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ=="], "unist-util-find-after": ["unist-util-find-after@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ=="],
@@ -1574,7 +1583,7 @@
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
"unstorage": ["unstorage@1.16.0", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.2", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.6", "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", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@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/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-WQ37/H5A7LcRPWfYOrDa1Ys02xAbpPJq6q5GkO88FBXVSQzHd7+BjEwfRqyaSWCv9MbsJy058GWjjPjcJ16GGA=="], "unstorage": ["unstorage@1.16.1", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.3", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.6", "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/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/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ=="],
"update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
@@ -1588,7 +1597,7 @@
"uuid": ["uuid@8.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw=="], "uuid": ["uuid@8.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw=="],
"validate-html-nesting": ["validate-html-nesting@1.2.2", "", {}, "sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg=="], "validate-html-nesting": ["validate-html-nesting@1.2.3", "", {}, "sha512-kdkWdCl6eCeLlRShJKbjVOU2kFKxMF8Ghu50n+crEoyx+VKm3FxAxF9z4DCy6+bbTOqNW0+jcIYRnjoIRzigRw=="],
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
@@ -1600,9 +1609,9 @@
"vite": ["vite@6.3.5", "", { "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-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="], "vite": ["vite@6.3.5", "", { "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-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="],
"vite-plugin-solid": ["vite-plugin-solid@2.11.6", "", { "dependencies": { "@babel/core": "^7.23.3", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^1.8.4", "merge-anything": "^5.1.7", "solid-refresh": "^0.6.3", "vitefu": "^1.0.4" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", "solid-js": "^1.7.2", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-Sl5CTqJTGyEeOsmdH6BOgalIZlwH3t4/y0RQuFLMGnvWMBvxb4+lq7x3BSiAw6etf0QexfNJW7HSOO/Qf7pigg=="], "vite-plugin-solid": ["vite-plugin-solid@2.11.7", "", { "dependencies": { "@babel/core": "^7.23.3", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^1.8.4", "merge-anything": "^5.1.7", "solid-refresh": "^0.6.3", "vitefu": "^1.0.4" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", "solid-js": "^1.7.2", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-5TgK1RnE449g0Ryxb9BXqem89RSy7fE8XGVCo+Gw84IHgPuPVP7nYNP6WBVAaY/0xw+OqfdQee+kusL0y3XYNg=="],
"vitefu": ["vitefu@1.0.6", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["vite"] }, "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA=="], "vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="],
"vscode-jsonrpc": ["vscode-jsonrpc@8.2.1", "", {}, "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ=="], "vscode-jsonrpc": ["vscode-jsonrpc@8.2.1", "", {}, "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ=="],
@@ -1622,9 +1631,9 @@
"widest-line": ["widest-line@5.0.0", "", { "dependencies": { "string-width": "^7.0.0" } }, "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA=="], "widest-line": ["widest-line@5.0.0", "", { "dependencies": { "string-width": "^7.0.0" } }, "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA=="],
"workerd": ["workerd@1.20250525.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250525.0", "@cloudflare/workerd-darwin-arm64": "1.20250525.0", "@cloudflare/workerd-linux-64": "1.20250525.0", "@cloudflare/workerd-linux-arm64": "1.20250525.0", "@cloudflare/workerd-windows-64": "1.20250525.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-SXJgLREy/Aqw2J71Oah0Pbu+SShbqbTExjVQyRBTM1r7MG7fS5NUlknhnt6sikjA/t4cO09Bi8OJqHdTkrcnYQ=="], "workerd": ["workerd@1.20250709.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250709.0", "@cloudflare/workerd-darwin-arm64": "1.20250709.0", "@cloudflare/workerd-linux-64": "1.20250709.0", "@cloudflare/workerd-linux-arm64": "1.20250709.0", "@cloudflare/workerd-windows-64": "1.20250709.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-BqLPpmvRN+TYUSG61OkWamsGdEuMwgvabP8m0QOHIfofnrD2YVyWqE1kXJ0GH5EsVEuWamE5sR8XpTfsGBmIpg=="],
"wrangler": ["wrangler@4.19.1", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.3.2", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20250525.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.17", "workerd": "1.20250525.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250525.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-b+ed2SJKauHgndl4Im1wHE+FeSSlrdlEZNuvpc8q/94k4EmRxRkXnwBAsVWuicBxG3HStFLQPGGlvL8wGKTtHw=="], "wrangler": ["wrangler@4.24.3", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.3.3", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20250709.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.17", "workerd": "1.20250709.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250709.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-stB1Wfs5NKlspsAzz8SBujBKsDqT5lpCyrL+vSUMy3uueEtI1A5qyORbKoJhIguEbwHfWS39mBsxzm6Vm1J2cg=="],
"wrap-ansi": ["wrap-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q=="], "wrap-ansi": ["wrap-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q=="],
@@ -1644,8 +1653,6 @@
"yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
"yaml": ["yaml@2.8.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ=="],
"yargs": ["yargs@18.0.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^7.2.0", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg=="], "yargs": ["yargs@18.0.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^7.2.0", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg=="],
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
@@ -1656,11 +1663,13 @@
"yoctocolors": ["yoctocolors@2.1.1", "", {}, "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ=="], "yoctocolors": ["yoctocolors@2.1.1", "", {}, "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ=="],
"youch": ["youch@3.3.4", "", { "dependencies": { "cookie": "^0.7.1", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg=="], "youch": ["youch@4.1.0-beta.10", "", { "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-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="],
"youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="],
"zod": ["zod@3.25.49", "", {}, "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q=="], "zod": ["zod@3.25.49", "", {}, "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q=="],
"zod-openapi": ["zod-openapi@4.2.4", "", { "peerDependencies": { "zod": "^3.21.4" } }, "sha512-tsrQpbpqFCXqVXUzi3TPwFhuMtLN3oNZobOtYnK6/5VkXsNdnIgyNr4r8no4wmYluaxzN3F7iS+8xCW8BmMQ8g=="], "zod-openapi": ["zod-openapi@4.1.0", "", { "peerDependencies": { "zod": "^3.21.4" } }, "sha512-bRCwRYhEO9CmFLyKgJX8h6j1dRtRiwOe+TLzMVPyV0pRW5vRIgb1rLgIGcuRZ5z3MmSVrZqbv3yva4IJrtZK4g=="],
"zod-to-json-schema": ["zod-to-json-schema@3.24.5", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="], "zod-to-json-schema": ["zod-to-json-schema@3.24.5", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="],
@@ -1678,25 +1687,21 @@
"@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.2.8", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA=="], "@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.2.8", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA=="],
"@ampproject/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], "@ampproject/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="],
"@astrojs/mdx/@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.2", "", { "dependencies": { "@astrojs/internal-helpers": "0.6.1", "@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.1.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.2.1", "smol-toml": "^1.3.1", "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-bO35JbWpVvyKRl7cmSJD822e8YA8ThR/YbUsciWNA7yTcqpIAL2hJDToWP5KcZBWxGT6IOdOkHSXARSNZc4l/Q=="], "@astrojs/mdx/@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.2", "", { "dependencies": { "@astrojs/internal-helpers": "0.6.1", "@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.1.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.2.1", "smol-toml": "^1.3.1", "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-bO35JbWpVvyKRl7cmSJD822e8YA8ThR/YbUsciWNA7yTcqpIAL2hJDToWP5KcZBWxGT6IOdOkHSXARSNZc4l/Q=="],
"@astrojs/sitemap/zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
"@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], "@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
"@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], "@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="],
"@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@emnapi/runtime/tslib": ["tslib@2.6.3", "", {}, "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="], "@jridgewell/gen-mapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="],
"@jridgewell/gen-mapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
"@openauthjs/openauth/@standard-schema/spec": ["@standard-schema/spec@1.0.0-beta.3", "", {}, "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw=="], "@openauthjs/openauth/@standard-schema/spec": ["@standard-schema/spec@1.0.0-beta.3", "", {}, "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw=="],
@@ -1716,26 +1721,24 @@
"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/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/zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
"babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="], "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="],
"bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], "bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
"eventsource/eventsource-parser": ["eventsource-parser@3.0.2", "", {}, "sha512-6RxOBZ/cYgd8usLwsEl+EC09Au/9BcmCKYF2/xbml6DNczf7nv0MQb+7BA2F+li6//I+28VNlQR37XfQtcAJuA=="],
"express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
"get-source/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"hast-util-to-parse5/property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="], "hast-util-to-parse5/property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="],
"http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
"miniflare/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], "miniflare/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
"miniflare/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=="], "miniflare/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=="],
"miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], "miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="],
"opencode/remeda": ["remeda@2.22.3", "", { "dependencies": { "type-fest": "^4.40.1" } }, "sha512-Ka6965m9Zu9OLsysWxVf3jdJKmp6+PKzDv7HWHinEevf0JOJ9y02YpjiC/sKxRpCqGhVyvm1U+0YIj+E6DMgKw=="],
"opencontrol/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.6.1", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="], "opencontrol/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.6.1", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="],
"opencontrol/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="], "opencontrol/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
@@ -1760,6 +1763,8 @@
"sst/jose": ["jose@5.2.3", "", {}, "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA=="], "sst/jose": ["jose@5.2.3", "", {}, "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA=="],
"to-buffer/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
"unicode-trie/pako": ["pako@0.2.9", "", {}, "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="], "unicode-trie/pako": ["pako@0.2.9", "", {}, "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="],
"unstorage/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "unstorage/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
@@ -1768,9 +1773,9 @@
"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/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=="],
"yargs/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], "xml2js/sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="],
"youch/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], "yargs/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="],
"@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/@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="],
@@ -1782,10 +1787,10 @@
"ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"opencontrol/@modelcontextprotocol/sdk/pkce-challenge": ["pkce-challenge@4.1.0", "", {}, "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="], "opencontrol/@modelcontextprotocol/sdk/pkce-challenge": ["pkce-challenge@4.1.0", "", {}, "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="],
"opencontrol/@modelcontextprotocol/sdk/zod": ["zod@3.25.49", "", {}, "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q=="],
"opencontrol/@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.24.5", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="], "opencontrol/@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.24.5", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="],
"prebuild-install/tar-fs/tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], "prebuild-install/tar-fs/tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
+3 -1
View File
@@ -28,6 +28,7 @@
}, },
"dependencies": { "dependencies": {
"@clack/prompts": "0.11.0", "@clack/prompts": "0.11.0",
"@hono/zod-validator": "0.4.2",
"@modelcontextprotocol/sdk": "1.15.1", "@modelcontextprotocol/sdk": "1.15.1",
"@openauthjs/openauth": "0.4.3", "@openauthjs/openauth": "0.4.3",
"ai": "catalog:", "ai": "catalog:",
@@ -42,6 +43,7 @@
"vscode-jsonrpc": "8.2.1", "vscode-jsonrpc": "8.2.1",
"xdg-basedir": "5.1.0", "xdg-basedir": "5.1.0",
"yargs": "18.0.0", "yargs": "18.0.0",
"zod": "catalog:" "zod": "catalog:",
"zod-openapi": "4.1.0"
} }
} }
+11 -13
View File
@@ -66,20 +66,18 @@ export namespace BunProc {
return result return result
}) })
if (parsed.dependencies[pkg] === version) return mod if (parsed.dependencies[pkg] === version) return mod
await BunProc.run(
[ // Build command arguments
"add", const args = ["add", "--force", "--exact", "--cwd", Global.Path.cache, pkg + "@" + version]
"--force",
"--exact", // Let Bun handle registry resolution:
"--cwd", // - If .npmrc files exist, Bun will use them automatically
Global.Path.cache, // - If no .npmrc files exist, Bun will default to https://registry.npmjs.org
"--registry=https://registry.npmjs.org", log.info("installing package using Bun's default registry resolution", { pkg, version })
pkg + "@" + version,
], await BunProc.run(args, {
{
cwd: Global.Path.cache, cwd: Global.Path.cache,
}, }).catch((e) => {
).catch((e) => {
throw new InstallFailedError( throw new InstallFailedError(
{ pkg, version }, { pkg, version },
{ {
@@ -0,0 +1,235 @@
import { $ } from "bun"
import path from "path"
import { exec } from "child_process"
import * as prompts from "@clack/prompts"
import { map, pipe, sortBy, values } from "remeda"
import { UI } from "../ui"
import { cmd } from "./cmd"
import { ModelsDev } from "../../provider/models"
import { App } from "../../app/app"
const WORKFLOW_FILE = ".github/workflows/opencode.yml"
export const InstallGithubCommand = cmd({
command: "install-github",
describe: "install the GitHub agent",
async handler() {
await App.provide({ cwd: process.cwd() }, async () => {
UI.empty()
prompts.intro("Install GitHub agent")
const app = await getAppInfo()
await installGitHubApp()
const providers = await ModelsDev.get()
const provider = await promptProvider()
const model = await promptModel()
//const key = await promptKey()
await addWorkflowFiles()
printNextSteps()
function printNextSteps() {
let step2
if (provider === "amazon-bedrock") {
step2 =
"Configure OIDC in AWS - https://docs.github.com/en/actions/how-tos/security-for-github-actions/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services"
} else {
const url = `https://github.com/organizations/${app.owner}/settings/secrets/actions`
const env = providers[provider].env
const envStr =
env.length === 1
? `\`${env[0]}\` secret`
: `\`${[env.slice(0, -1).join("\`, \`"), ...env.slice(-1)].join("\` and \`")}\` secrets`
step2 = `Add ${envStr} for ${providers[provider].name} - ${url}`
}
prompts.outro(
[
"Next steps:",
` 1. Commit "${WORKFLOW_FILE}" file and push`,
` 2. ${step2}`,
" 3. Learn how to use the GitHub agent - https://docs.opencode.ai/docs/github/getting-started",
].join("\n"),
)
}
async function getAppInfo() {
const app = App.info()
if (!app.git) {
prompts.log.error(`Could not find git repository. Please run this command from a git repository.`)
throw new UI.CancelledError()
}
// Get repo info
const info = await $`git remote get-url origin`.quiet().nothrow().text()
// match https or git pattern
// ie. https://github.com/sst/opencode.git
// ie. git@github.com:sst/opencode.git
const parsed = info.match(/git@github\.com:(.*)\.git/) ?? info.match(/github\.com\/(.*)\.git/)
if (!parsed) {
prompts.log.error(`Could not find git repository. Please run this command from a git repository.`)
throw new UI.CancelledError()
}
const [owner, repo] = parsed[1].split("/")
return { owner, repo, root: app.path.root }
}
async function promptProvider() {
const priority: Record<string, number> = {
anthropic: 0,
"github-copilot": 1,
openai: 2,
google: 3,
}
let provider = await prompts.select({
message: "Select provider",
maxItems: 8,
options: [
...pipe(
providers,
values(),
sortBy(
(x) => priority[x.id] ?? 99,
(x) => x.name ?? x.id,
),
map((x) => ({
label: x.name,
value: x.id,
hint: priority[x.id] === 0 ? "recommended" : undefined,
})),
),
{
value: "other",
label: "Other",
},
],
})
if (prompts.isCancel(provider)) throw new UI.CancelledError()
if (provider === "other") {
provider = await prompts.text({
message: "Enter provider id",
validate: (x) => (x.match(/^[a-z-]+$/) ? undefined : "a-z and hyphens only"),
})
if (prompts.isCancel(provider)) throw new UI.CancelledError()
provider = provider.replace(/^@ai-sdk\//, "")
if (prompts.isCancel(provider)) throw new UI.CancelledError()
prompts.log.warn(
`This only stores a credential for ${provider} - you will need configure it in opencode.json, check the docs for examples.`,
)
}
return provider
}
async function promptModel() {
const providerData = providers[provider]!
const model = await prompts.select({
message: "Select model",
maxItems: 8,
options: pipe(
providerData.models,
values(),
sortBy((x) => x.name ?? x.id),
map((x) => ({
label: x.name ?? x.id,
value: x.id,
})),
),
})
if (prompts.isCancel(model)) throw new UI.CancelledError()
return model
}
async function installGitHubApp() {
const s = prompts.spinner()
s.start("Installing GitHub app")
// Get installation
const installation = await getInstallation()
if (installation) return s.stop("GitHub app already installed")
// Open browser
const url = "https://github.com/apps/opencode-agent"
const command =
process.platform === "darwin"
? `open "${url}"`
: process.platform === "win32"
? `start "${url}"`
: `xdg-open "${url}"`
exec(command, (error) => {
if (error) {
prompts.log.warn(`Could not open browser. Please visit: ${url}`)
}
})
// Wait for installation
s.message("Waiting for GitHub app to be installed")
const MAX_RETRIES = 60
let retries = 0
do {
const installation = await getInstallation()
if (installation) break
if (retries > MAX_RETRIES) {
s.stop(
`Failed to detect GitHub app installation. Make sure to install the app for the \`${app.owner}/${app.repo}\` repository.`,
)
throw new UI.CancelledError()
}
retries++
await new Promise((resolve) => setTimeout(resolve, 1000))
} while (true)
s.stop("Installed GitHub app")
async function getInstallation() {
return await fetch(`https://api.opencode.ai/get_github_app_installation?owner=${app.owner}&repo=${app.repo}`)
.then((res) => res.json())
.then((data) => data.installation)
}
}
async function addWorkflowFiles() {
const envStr =
provider === "amazon-bedrock"
? ""
: `\n env:${providers[provider].env.map((e) => `\n ${e}: \${{ secrets.${e} }}`).join("")}`
await Bun.write(
path.join(app.root, WORKFLOW_FILE),
`
name: opencode
on:
issue_comment:
types: [created]
jobs:
opencode:
if: startsWith(github.event.comment.body, 'hey opencode')
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Run opencode
uses: sst/opencode/sdks/github@github-v1${envStr}
with:
model: ${provider}/${model}
`.trim(),
)
prompts.log.success(`Added workflow file: "${WORKFLOW_FILE}"`)
}
})
},
})
+11 -2
View File
@@ -81,8 +81,10 @@ export namespace Config {
.object({ .object({
leader: z.string().optional().default("ctrl+x").describe("Leader key for keybind combinations"), leader: z.string().optional().default("ctrl+x").describe("Leader key for keybind combinations"),
app_help: z.string().optional().default("<leader>h").describe("Show help dialog"), app_help: z.string().optional().default("<leader>h").describe("Show help dialog"),
switch_mode: z.string().optional().default("tab").describe("Switch mode"), switch_mode: z.string().optional().default("tab").describe("Next mode"),
switch_mode_reverse: z.string().optional().default("shift+tab").describe("Previous Mode"),
editor_open: z.string().optional().default("<leader>e").describe("Open external editor"), editor_open: z.string().optional().default("<leader>e").describe("Open external editor"),
session_export: z.string().optional().default("<leader>x").describe("Export session to editor"),
session_new: z.string().optional().default("<leader>n").describe("Create a new session"), session_new: z.string().optional().default("<leader>n").describe("Create a new session"),
session_list: z.string().optional().default("<leader>l").describe("List all sessions"), session_list: z.string().optional().default("<leader>l").describe("List all sessions"),
session_share: z.string().optional().default("<leader>s").describe("Share current session"), session_share: z.string().optional().default("<leader>s").describe("Share current session"),
@@ -123,6 +125,11 @@ export namespace Config {
ref: "KeybindsConfig", ref: "KeybindsConfig",
}) })
export const Layout = z.enum(["auto", "stretch"]).openapi({
ref: "LayoutConfig",
})
export type Layout = z.infer<typeof Layout>
export const Info = z export const Info = z
.object({ .object({
$schema: z.string().optional().describe("JSON schema reference for configuration validation"), $schema: z.string().optional().describe("JSON schema reference for configuration validation"),
@@ -149,7 +156,8 @@ export namespace Config {
plan: Mode.optional(), plan: Mode.optional(),
}) })
.catchall(Mode) .catchall(Mode)
.optional(), .optional()
.describe("Modes configuration, see https://opencode.ai/docs/modes"),
log_level: Log.Level.optional().describe("Minimum log level to write to log files"), log_level: Log.Level.optional().describe("Minimum log level to write to log files"),
provider: z provider: z
.record( .record(
@@ -162,6 +170,7 @@ export namespace Config {
.describe("Custom provider configurations and model overrides"), .describe("Custom provider configurations and model overrides"),
mcp: z.record(z.string(), Mcp).optional().describe("MCP (Model Context Protocol) server configurations"), mcp: z.record(z.string(), Mcp).optional().describe("MCP (Model Context Protocol) server configurations"),
instructions: z.array(z.string()).optional().describe("Additional instruction files or patterns to include"), instructions: z.array(z.string()).optional().describe("Additional instruction files or patterns to include"),
layout: Layout.optional().describe("Layout to use for the TUI"),
experimental: z experimental: z
.object({ .object({
hook: z hook: z
+2
View File
@@ -16,6 +16,7 @@ import { TuiCommand } from "./cli/cmd/tui"
import { DebugCommand } from "./cli/cmd/debug" import { DebugCommand } from "./cli/cmd/debug"
import { StatsCommand } from "./cli/cmd/stats" import { StatsCommand } from "./cli/cmd/stats"
import { McpCommand } from "./cli/cmd/mcp" import { McpCommand } from "./cli/cmd/mcp"
import { InstallGithubCommand } from "./cli/cmd/install-github"
const cancel = new AbortController() const cancel = new AbortController()
@@ -76,6 +77,7 @@ const cli = yargs(hideBin(process.argv))
.command(ServeCommand) .command(ServeCommand)
.command(ModelsCommand) .command(ModelsCommand)
.command(StatsCommand) .command(StatsCommand)
.command(InstallGithubCommand)
.fail((msg) => { .fail((msg) => {
if (msg.startsWith("Unknown argument") || msg.startsWith("Not enough non-option arguments")) { if (msg.startsWith("Unknown argument") || msg.startsWith("Not enough non-option arguments")) {
cli.showHelp("log") cli.showHelp("log")
+4 -2
View File
@@ -17,6 +17,7 @@ import {
import PROMPT_INITIALIZE from "../session/prompt/initialize.txt" import PROMPT_INITIALIZE from "../session/prompt/initialize.txt"
import PROMPT_PLAN from "../session/prompt/plan.txt" import PROMPT_PLAN from "../session/prompt/plan.txt"
import PROMPT_ANTHROPIC_SPOOF from "../session/prompt/anthropic_spoof.txt"
import { App } from "../app/app" import { App } from "../app/app"
import { Bus } from "../bus" import { Bus } from "../bus"
@@ -507,7 +508,7 @@ export namespace Session {
const small = (await Provider.getSmallModel(input.providerID)) ?? model const small = (await Provider.getSmallModel(input.providerID)) ?? model
generateText({ generateText({
maxOutputTokens: input.providerID === "google" ? 1024 : 20, maxOutputTokens: input.providerID === "google" ? 1024 : 20,
providerOptions: model.info.options, providerOptions: small.info.options,
messages: [ messages: [
...SystemPrompt.title(input.providerID).map( ...SystemPrompt.title(input.providerID).map(
(x): ModelMessage => ({ (x): ModelMessage => ({
@@ -546,7 +547,8 @@ export namespace Session {
msgs.push({ info: userMsg, parts: userParts }) msgs.push({ info: userMsg, parts: userParts })
const mode = await Mode.get(input.mode ?? "build") const mode = await Mode.get(input.mode ?? "build")
let system = mode.prompt ? [mode.prompt] : SystemPrompt.provider(input.providerID, input.modelID) let system = input.providerID === "anthropic" ? [PROMPT_ANTHROPIC_SPOOF.trim()] : []
system.push(...(mode.prompt ? [mode.prompt] : SystemPrompt.provider(input.modelID)))
system.push(...(await SystemPrompt.environment())) system.push(...(await SystemPrompt.environment()))
system.push(...(await SystemPrompt.custom())) system.push(...(await SystemPrompt.custom()))
// max 2 system prompt messages for caching purposes // max 2 system prompt messages for caching purposes
-1
View File
@@ -30,7 +30,6 @@ export namespace Mode {
write: false, write: false,
edit: false, edit: false,
patch: false, patch: false,
bash: false,
}, },
}, },
}, },
@@ -0,0 +1,155 @@
You are opencode, an interactive CLI agent specializing in software engineering tasks. Your primary goal is to help users safely and efficiently, adhering strictly to the following instructions and utilizing your available tools.
# Core Mandates
- **Conventions:** Rigorously adhere to existing project conventions when reading or modifying code. Analyze surrounding code, tests, and configuration first.
- **Libraries/Frameworks:** NEVER assume a library/framework is available or appropriate. Verify its established usage within the project (check imports, configuration files like 'package.json', 'Cargo.toml', 'requirements.txt', 'build.gradle', etc., or observe neighboring files) before employing it.
- **Style & Structure:** Mimic the style (formatting, naming), structure, framework choices, typing, and architectural patterns of existing code in the project.
- **Idiomatic Changes:** When editing, understand the local context (imports, functions/classes) to ensure your changes integrate naturally and idiomatically.
- **Comments:** Add code comments sparingly. Focus on *why* something is done, especially for complex logic, rather than *what* is done. Only add high-value comments if necessary for clarity or if requested by the user. Do not edit comments that are separate from the code you are changing. *NEVER* talk to the user or describe your changes through comments.
- **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions.
- **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it.
- **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked.
- **Path Construction:** Before using any file system tool (e.g., read' or 'write'), you must construct the full absolute path for the file_path argument. Always combine the absolute path of the project's root directory with the file's path relative to the root. For example, if the project root is /path/to/project/ and the file is foo/bar/baz.txt, the final path you must use is /path/to/project/foo/bar/baz.txt. If the user provides a relative path, you must resolve it against the root directory to create an absolute path.
- **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes.
# Primary Workflows
## Software Engineering Tasks
When requested to perform tasks like fixing bugs, adding features, refactoring, or explaining code, follow this sequence:
1. **Understand:** Think about the user's request and the relevant codebase context. Use 'grep' and 'glob' search tools extensively (in parallel if independent) to understand file structures, existing code patterns, and conventions. Use 'read' to understand context and validate any assumptions you may have.
2. **Plan:** Build a coherent and grounded (based on the understanding in step 1) plan for how you intend to resolve the user's task. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should try to use a self-verification loop by writing unit tests if relevant to the task. Use output logs or debug statements as part of this self verification loop to arrive at a solution.
3. **Implement:** Use the available tools (e.g., 'edit', 'write' 'bash' ...) to act on the plan, strictly adhering to the project's established conventions (detailed under 'Core Mandates').
4. **Verify (Tests):** If applicable and feasible, verify the changes using the project's testing procedures. Identify the correct test commands and frameworks by examining 'README' files, build/package configuration (e.g., 'package.json'), or existing test execution patterns. NEVER assume standard test commands.
5. **Verify (Standards):** VERY IMPORTANT: After making code changes, execute the project-specific build, linting and type-checking commands (e.g., 'tsc', 'npm run lint', 'ruff check .') that you have identified for this project (or obtained from the user). This ensures code quality and adherence to standards. If unsure about these commands, you can ask the user if they'd like you to run them and if so how to.
## New Applications
**Goal:** Autonomously implement and deliver a visually appealing, substantially complete, and functional prototype. Utilize all tools at your disposal to implement the application. Some tools you may especially find useful are 'write', 'edit' and 'bash'.
1. **Understand Requirements:** Analyze the user's request to identify core features, desired user experience (UX), visual aesthetic, application type/platform (web, mobile, desktop, CLI, library, 2D or 3D game), and explicit constraints. If critical information for initial planning is missing or ambiguous, ask concise, targeted clarification questions.
2. **Propose Plan:** Formulate an internal development plan. Present a clear, concise, high-level summary to the user. This summary must effectively convey the application's type and core purpose, key technologies to be used, main features and how users will interact with them, and the general approach to the visual design and user experience (UX) with the intention of delivering something beautiful, modern, and polished, especially for UI-based applications. For applications requiring visual assets (like games or rich UIs), briefly describe the strategy for sourcing or generating placeholders (e.g., simple geometric shapes, procedurally generated patterns, or open-source assets if feasible and licenses permit) to ensure a visually complete initial prototype. Ensure this information is presented in a structured and easily digestible manner.
3. **User Approval:** Obtain user approval for the proposed plan.
4. **Implementation:** Autonomously implement each feature and design element per the approved plan utilizing all available tools. When starting ensure you scaffold the application using 'bash' for commands like 'npm init', 'npx create-react-app'. Aim for full scope completion. Proactively create or source necessary placeholder assets (e.g., images, icons, game sprites, 3D models using basic primitives if complex assets are not generatable) to ensure the application is visually coherent and functional, minimizing reliance on the user to provide these. If the model can generate simple assets (e.g., a uniformly colored square sprite, a simple 3D cube), it should do so. Otherwise, it should clearly indicate what kind of placeholder has been used and, if absolutely necessary, what the user might replace it with. Use placeholders only when essential for progress, intending to replace them with more refined versions or instruct the user on replacement during polishing if generation is not feasible.
5. **Verify:** Review work against the original request, the approved plan. Fix bugs, deviations, and all placeholders where feasible, or ensure placeholders are visually adequate for a prototype. Ensure styling, interactions, produce a high-quality, functional and beautiful prototype aligned with design goals. Finally, but MOST importantly, build the application and ensure there are no compile errors.
6. **Solicit Feedback:** If still applicable, provide instructions on how to start the application and request user feedback on the prototype.
# Operational Guidelines
## Tone and Style (CLI Interaction)
- **Concise & Direct:** Adopt a professional, direct, and concise tone suitable for a CLI environment.
- **Minimal Output:** Aim for fewer than 3 lines of text output (excluding tool use/code generation) per response whenever practical. Focus strictly on the user's query.
- **Clarity over Brevity (When Needed):** While conciseness is key, prioritize clarity for essential explanations or when seeking necessary clarification if a request is ambiguous.
- **No Chitchat:** Avoid conversational filler, preambles ("Okay, I will now..."), or postambles ("I have finished the changes..."). Get straight to the action or answer.
- **Formatting:** Use GitHub-flavored Markdown. Responses will be rendered in monospace.
- **Tools vs. Text:** Use tools for actions, text output *only* for communication. Do not add explanatory comments within tool calls or code blocks unless specifically part of the required code/command itself.
- **Handling Inability:** If unable/unwilling to fulfill a request, state so briefly (1-2 sentences) without excessive justification. Offer alternatives if appropriate.
## Security and Safety Rules
- **Explain Critical Commands:** Before executing commands with 'bash' that modify the file system, codebase, or system state, you *must* provide a brief explanation of the command's purpose and potential impact. Prioritize user understanding and safety. You should not ask permission to use the tool; the user will be presented with a confirmation dialogue upon use (you do not need to tell them this).
- **Security First:** Always apply security best practices. Never introduce code that exposes, logs, or commits secrets, API keys, or other sensitive information.
## Tool Usage
- **File Paths:** Always use absolute paths when referring to files with tools like 'read' or 'write'. Relative paths are not supported. You must provide an absolute path.
- **Parallelism:** Execute multiple independent tool calls in parallel when feasible (i.e. searching the codebase).
- **Command Execution:** Use the 'bash' tool for running shell commands, remembering the safety rule to explain modifying commands first.
- **Background Processes:** Use background processes (via \`&\`) for commands that are unlikely to stop on their own, e.g. \`node server.js &\`. If unsure, ask the user.
- **Interactive Commands:** Try to avoid shell commands that are likely to require user interaction (e.g. \`git rebase -i\`). Use non-interactive versions of commands (e.g. \`npm init -y\` instead of \`npm init\`) when available, and otherwise remind the user that interactive shell commands are not supported and may cause hangs until canceled by the user.
- **Respect User Confirmations:** Most tool calls (also denoted as 'function calls') will first require confirmation from the user, where they will either approve or cancel the function call. If a user cancels a function call, respect their choice and do _not_ try to make the function call again. It is okay to request the tool call again _only_ if the user requests that same tool call on a subsequent prompt. When a user cancels a function call, assume best intentions from the user and consider inquiring if they prefer any alternative paths forward.
## Interaction Details
- **Help Command:** The user can use '/help' to display help information.
- **Feedback:** To report a bug or provide feedback, please use the /bug command.
# Examples (Illustrating Tone and Workflow)
<example>
user: 1 + 2
model: 3
</example>
<example>
user: is 13 a prime number?
model: true
</example>
<example>
user: list files here.
model: [tool_call: ls for path '/path/to/project']
</example>
<example>
user: start the server implemented in server.js
model: [tool_call: bash for 'node server.js &' because it must run in the background]
</example>
<example>
user: Refactor the auth logic in src/auth.py to use the requests library instead of urllib.
model: Okay, I can refactor 'src/auth.py'.
First, I'll analyze the code and check for a test safety net before planning any changes.
[tool_call: glob for path 'tests/test_auth.py']
[tool_call: read for absolute_path '/path/to/tests/test_auth.py']
(After analysis)
Great, 'tests/test_auth.py' exists and covers the core authentication logic. With this safety net in place, I can safely plan the refactoring.
I'll also confirm 'requests' is a dependency.
[tool_call: read for absolute_path '/path/to/requirements.txt']
(After analysis)
Looks good, 'requests' is available.
Here's the plan:
1. Replace the 'urllib' calls with 'requests'.
2. Add proper 'try...except' error handling for the new network calls.
3. Remove the old 'urllib' import.
4. Run the project's linter and tests to verify the changes.
Should I proceed?
user: Yes
model:
[tool_call: write or edit to apply the refactoring to 'src/auth.py']
Refactoring complete. Running verification...
[tool_call: bash for 'ruff check src/auth.py && pytest']
(After verification passes)
All checks passed. This is a stable checkpoint.
<example>
user: Delete the temp directory.
model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete the directory and all its contents.
</example>
<example>
user: Write tests for someFile.ts
model:
Okay, I can write those tests. First, I'll read \`someFile.ts\` to understand its functionality.
[tool_call: read for absolute_path '/path/to/someFile.ts' or use glob to find \`someFile.ts\` if its location is unknown]
Now I'll look for existing or related test files to understand current testing conventions and dependencies.
[tool_call: glob for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory]
(After reviewing existing tests and the file content)
[tool_call: write to create /path/to/someFile.test.ts with the test code]
I've written the tests. Now I'll run the project's test command to verify them.
[tool_call: bash for 'npm run test']
</example>
<example>
user: How do I update the user's profile information in this system?
model:
I'm not immediately sure how user profile information is updated. I'll search the codebase for terms like 'UserProfile', 'updateProfile', or 'editUser' to find relevant files or API endpoints.
[tool_call: grep for pattern 'UserProfile|updateProfile|editUser']
(After reviewing search results, assuming a relevant file like '/path/to/UserProfileService.java' was found)
Okay, \`/path/to/UserProfileService.java\` seems like the most relevant file. I'll read its content to understand how updates are handled.
[tool_call: read for absolute_path '/path/to/UserProfileService.java']
(After reading the file)
It appears the \`updateUserProfile\` method in \`UserProfileService.java\` is responsible for this. It expects a user ID and a \`UserProfileDTO\` object...
</example>
<example>
user: Where are all the 'app.config' files in this project? I need to check their settings.
model:
[tool_call: glob for pattern '**/app.config']
(Assuming GlobTool returns a list of paths like ['/path/to/moduleA/app.config', '/path/to/moduleB/app.config'])
I found the following 'app.config' files:
- /path/to/moduleA/app.config
- /path/to/moduleB/app.config
To help you check their settings, I can read their contents. Which one would you like to start with, or should I read all of them?
</example>
# Final Reminder
Your core function is efficient and safe assistance. Balance extreme conciseness with the crucial need for clarity, especially regarding safety and potential system modifications. Always prioritize user control and project conventions. Never make assumptions about the contents of files; instead use 'read' to ensure you aren't making broad assumptions. Finally, you are an agent - please keep going until the user's query is completely resolved.
+23 -8
View File
@@ -1,14 +1,29 @@
<task> <task>
Generate a conversation thread title based on the first user message. Generate a conversation thread title from the user message.
</task> </task>
<requirements> <context>
- Maximum 50 characters You are generating titles for a coding assistant conversation.
- Single line only - NO newlines or line breaks </context>
- Create a descriptive thread name that captures the topic
- No quotes, colons, or special formatting <rules>
- Do not include explanatory text like "Title:" or similar prefixes - Max 50 chars, single line
</requirements> - Focus on the specific action or question
- Keep technical terms, numbers, and filenames exactly as written
- Preserve HTTP status codes (401, 404, 500, etc) as numbers
- For file references, include the filename
- Avoid filler words: the, this, my, a, an, properly
- NEVER assume their tech stack or domain
- Use -ing verbs consistently for actions
- Write like a chat thread title, not a blog post
</rules>
<examples>
"debug 500 errors in production" → "Debugging production 500 errors"
"refactor user service" → "Refactoring user service"
"why is app.js failing" → "Analyzing app.js failure"
"implement rate limiting" → "Implementing rate limiting"
</examples>
<format> <format>
Return only the thread title text on a single line with no newlines, explanations, or additional formatting. Return only the thread title text on a single line with no newlines, explanations, or additional formatting.
+3 -2
View File
@@ -8,14 +8,15 @@ import os from "os"
import PROMPT_ANTHROPIC from "./prompt/anthropic.txt" import PROMPT_ANTHROPIC from "./prompt/anthropic.txt"
import PROMPT_BEAST from "./prompt/beast.txt" import PROMPT_BEAST from "./prompt/beast.txt"
import PROMPT_GEMINI from "./prompt/gemini.txt"
import PROMPT_ANTHROPIC_SPOOF from "./prompt/anthropic_spoof.txt" import PROMPT_ANTHROPIC_SPOOF from "./prompt/anthropic_spoof.txt"
import PROMPT_SUMMARIZE from "./prompt/summarize.txt" import PROMPT_SUMMARIZE from "./prompt/summarize.txt"
import PROMPT_TITLE from "./prompt/title.txt" import PROMPT_TITLE from "./prompt/title.txt"
export namespace SystemPrompt { export namespace SystemPrompt {
export function provider(providerID: string, modelID: string) { export function provider(modelID: string) {
if (providerID === "anthropic") return [PROMPT_ANTHROPIC_SPOOF.trim(), PROMPT_ANTHROPIC]
if (modelID.includes("gpt-") || modelID.includes("o1") || modelID.includes("o3")) return [PROMPT_BEAST] if (modelID.includes("gpt-") || modelID.includes("o1") || modelID.includes("o3")) return [PROMPT_BEAST]
if (modelID.includes("gemini-")) return [PROMPT_GEMINI]
return [PROMPT_ANTHROPIC] return [PROMPT_ANTHROPIC]
} }
+2 -1
View File
@@ -38,7 +38,8 @@ export namespace Snapshot {
await $`git --git-dir ${git} add .`.quiet().cwd(app.path.cwd).nothrow() await $`git --git-dir ${git} add .`.quiet().cwd(app.path.cwd).nothrow()
log.info("added files") log.info("added files")
const result = await $`git --git-dir ${git} commit -m "snapshot" --author="opencode <mail@opencode.ai>"` const result =
await $`git --git-dir ${git} commit -m "snapshot" --no-gpg-sign --author="opencode <mail@opencode.ai>"`
.quiet() .quiet()
.cwd(app.path.cwd) .cwd(app.path.cwd)
.nothrow() .nothrow()
+4 -1
View File
@@ -86,7 +86,10 @@ export const EditTool = Tool.define({
output += `\nThis file has errors, please fix\n<file_diagnostics>\n${issues.map(LSP.Diagnostic.pretty).join("\n")}\n</file_diagnostics>\n` output += `\nThis file has errors, please fix\n<file_diagnostics>\n${issues.map(LSP.Diagnostic.pretty).join("\n")}\n</file_diagnostics>\n`
continue continue
} }
output += `\n<project_diagnostics>\n${file}\n${issues.map(LSP.Diagnostic.pretty).join("\n")}\n</project_diagnostics>\n` output += `\n<project_diagnostics>\n${file}\n${issues
.filter((item) => item.severity === 1)
.map(LSP.Diagnostic.pretty)
.join("\n")}\n</project_diagnostics>\n`
} }
return { return {
+4 -5
View File
@@ -55,12 +55,11 @@ export const GrepTool = Tool.define({
for (const line of lines) { for (const line of lines) {
if (!line) continue if (!line) continue
const parts = line.split(":", 3) const [filePath, lineNumStr, ...lineTextParts] = line.split(":")
if (parts.length < 3) continue if (!filePath || !lineNumStr || lineTextParts.length === 0) continue
const filePath = parts[0] const lineNum = parseInt(lineNumStr, 10)
const lineNum = parseInt(parts[1], 10) const lineText = lineTextParts.join(":")
const lineText = parts[2]
const file = Bun.file(filePath) const file = Bun.file(filePath)
const stats = await file.stat().catch(() => null) const stats = await file.stat().catch(() => null)
+53
View File
@@ -0,0 +1,53 @@
import { describe, expect, test } from "bun:test"
import fs from "fs/promises"
import path from "path"
describe("BunProc registry configuration", () => {
test("should not contain hardcoded registry parameters", async () => {
// Read the bun/index.ts file
const bunIndexPath = path.join(__dirname, "../src/bun/index.ts")
const content = await fs.readFile(bunIndexPath, "utf-8")
// Verify that no hardcoded registry is present
expect(content).not.toContain("--registry=")
expect(content).not.toContain("hasNpmRcConfig")
expect(content).not.toContain("NpmRc")
})
test("should use Bun's default registry resolution", async () => {
// Read the bun/index.ts file
const bunIndexPath = path.join(__dirname, "../src/bun/index.ts")
const content = await fs.readFile(bunIndexPath, "utf-8")
// Verify that it uses Bun's default resolution
expect(content).toContain("Bun's default registry resolution")
expect(content).toContain("Bun will use them automatically")
expect(content).toContain("No need to pass --registry flag")
})
test("should have correct command structure without registry", async () => {
// Read the bun/index.ts file
const bunIndexPath = path.join(__dirname, "../src/bun/index.ts")
const content = await fs.readFile(bunIndexPath, "utf-8")
// Extract the install function
const installFunctionMatch = content.match(/export async function install[\s\S]*?^ }/m)
expect(installFunctionMatch).toBeTruthy()
if (installFunctionMatch) {
const installFunction = installFunctionMatch[0]
// Verify expected arguments are present
expect(installFunction).toContain('"add"')
expect(installFunction).toContain('"--force"')
expect(installFunction).toContain('"--exact"')
expect(installFunction).toContain('"--cwd"')
expect(installFunction).toContain('Global.Path.cache')
expect(installFunction).toContain('pkg + "@" + version')
// Verify no registry argument is added
expect(installFunction).not.toContain('"--registry"')
expect(installFunction).not.toContain('args.push("--registry')
}
})
})
BIN
View File
Binary file not shown.
+19 -4
View File
@@ -205,11 +205,18 @@ func (a *App) SetClipboard(text string) tea.Cmd {
return tea.Sequence(cmds...) return tea.Sequence(cmds...)
} }
func (a *App) SwitchMode() (*App, tea.Cmd) { func (a *App) cycleMode(forward bool) (*App, tea.Cmd) {
if forward {
a.ModeIndex++ a.ModeIndex++
if a.ModeIndex >= len(a.Modes) { if a.ModeIndex >= len(a.Modes) {
a.ModeIndex = 0 a.ModeIndex = 0
} }
} else {
a.ModeIndex--
if a.ModeIndex < 0 {
a.ModeIndex = len(a.Modes) - 1
}
}
a.Mode = &a.Modes[a.ModeIndex] a.Mode = &a.Modes[a.ModeIndex]
modelID := a.Mode.Model.ModelID modelID := a.Mode.Model.ModelID
@@ -244,8 +251,16 @@ func (a *App) SwitchMode() (*App, tea.Cmd) {
} }
} }
func (a *App) SwitchMode() (*App, tea.Cmd) {
return a.cycleMode(true)
}
func (a *App) SwitchModeReverse() (*App, tea.Cmd) {
return a.cycleMode(false)
}
func (a *App) InitializeProvider() tea.Cmd { func (a *App) InitializeProvider() tea.Cmd {
providersResponse, err := a.Client.Config.Providers(context.Background()) providersResponse, err := a.Client.App.Providers(context.Background())
if err != nil { if err != nil {
slog.Error("Failed to list providers", "error", err) slog.Error("Failed to list providers", "error", err)
// TODO: notify user // TODO: notify user
@@ -340,7 +355,7 @@ func (a *App) InitializeProvider() tea.Cmd {
} }
func getDefaultModel( func getDefaultModel(
response *opencode.ConfigProvidersResponse, response *opencode.AppProvidersResponse,
provider opencode.Provider, provider opencode.Provider,
) *opencode.Model { ) *opencode.Model {
if match, ok := response.Default[provider.ID]; ok { if match, ok := response.Default[provider.ID]; ok {
@@ -603,7 +618,7 @@ func (a *App) ListMessages(ctx context.Context, sessionId string) ([]Message, er
} }
func (a *App) ListProviders(ctx context.Context) ([]opencode.Provider, error) { func (a *App) ListProviders(ctx context.Context) ([]opencode.Provider, error) {
response, err := a.Client.Config.Providers(ctx) response, err := a.Client.App.Providers(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+4
View File
@@ -0,0 +1,4 @@
package app
const MAX_CONTAINER_WIDTH = 86
const EDIT_DIFF_MAX_WIDTH = 180
+21 -8
View File
@@ -87,6 +87,7 @@ func (r CommandRegistry) Matches(msg tea.KeyPressMsg, leader bool) []Command {
const ( const (
AppHelpCommand CommandName = "app_help" AppHelpCommand CommandName = "app_help"
SwitchModeCommand CommandName = "switch_mode" SwitchModeCommand CommandName = "switch_mode"
SwitchModeReverseCommand CommandName = "switch_mode_reverse"
EditorOpenCommand CommandName = "editor_open" EditorOpenCommand CommandName = "editor_open"
SessionNewCommand CommandName = "session_new" SessionNewCommand CommandName = "session_new"
SessionListCommand CommandName = "session_list" SessionListCommand CommandName = "session_list"
@@ -94,6 +95,7 @@ const (
SessionUnshareCommand CommandName = "session_unshare" SessionUnshareCommand CommandName = "session_unshare"
SessionInterruptCommand CommandName = "session_interrupt" SessionInterruptCommand CommandName = "session_interrupt"
SessionCompactCommand CommandName = "session_compact" SessionCompactCommand CommandName = "session_compact"
SessionExportCommand CommandName = "session_export"
ToolDetailsCommand CommandName = "tool_details" ToolDetailsCommand CommandName = "tool_details"
ModelListCommand CommandName = "model_list" ModelListCommand CommandName = "model_list"
ThemeListCommand CommandName = "theme_list" ThemeListCommand CommandName = "theme_list"
@@ -155,15 +157,26 @@ func LoadFromConfig(config *opencode.Config) CommandRegistry {
}, },
{ {
Name: SwitchModeCommand, Name: SwitchModeCommand,
Description: "switch mode", Description: "next mode",
Keybindings: parseBindings("tab"), Keybindings: parseBindings("tab"),
}, },
{
Name: SwitchModeReverseCommand,
Description: "previous mode",
Keybindings: parseBindings("shift+tab"),
},
{ {
Name: EditorOpenCommand, Name: EditorOpenCommand,
Description: "open editor", Description: "open editor",
Keybindings: parseBindings("<leader>e"), Keybindings: parseBindings("<leader>e"),
Trigger: []string{"editor"}, Trigger: []string{"editor"},
}, },
{
Name: SessionExportCommand,
Description: "export conversation",
Keybindings: parseBindings("<leader>x"),
Trigger: []string{"export"},
},
{ {
Name: SessionNewCommand, Name: SessionNewCommand,
Description: "new session", Description: "new session",
@@ -217,12 +230,12 @@ func LoadFromConfig(config *opencode.Config) CommandRegistry {
Keybindings: parseBindings("<leader>t"), Keybindings: parseBindings("<leader>t"),
Trigger: []string{"themes"}, Trigger: []string{"themes"},
}, },
{ // {
Name: FileListCommand, // Name: FileListCommand,
Description: "list files", // Description: "list files",
Keybindings: parseBindings("<leader>f"), // Keybindings: parseBindings("<leader>f"),
Trigger: []string{"files"}, // Trigger: []string{"files"},
}, // },
{ {
Name: FileCloseCommand, Name: FileCloseCommand,
Description: "close file", Description: "close file",
@@ -323,7 +336,7 @@ func LoadFromConfig(config *opencode.Config) CommandRegistry {
Name: AppExitCommand, Name: AppExitCommand,
Description: "exit the app", Description: "exit the app",
Keybindings: parseBindings("ctrl+c", "<leader>q"), Keybindings: parseBindings("ctrl+c", "<leader>q"),
Trigger: []string{"exit", "quit"}, Trigger: []string{"exit", "quit", "q"},
}, },
} }
registry := make(CommandRegistry) registry := make(CommandRegistry)
@@ -77,7 +77,6 @@ func (c *CommandCompletionProvider) GetChildEntries(
return items, nil return items, nil
} }
// Use fuzzy matching for commands
var commandNames []string var commandNames []string
commandMap := make(map[string]CompletionSuggestion) commandMap := make(map[string]CompletionSuggestion)
@@ -86,17 +85,13 @@ func (c *CommandCompletionProvider) GetChildEntries(
continue continue
} }
space := space - lipgloss.Width(cmd.PrimaryTrigger()) space := space - lipgloss.Width(cmd.PrimaryTrigger())
// Add all triggers as searchable options
for _, trigger := range cmd.Trigger { for _, trigger := range cmd.Trigger {
commandNames = append(commandNames, trigger) commandNames = append(commandNames, trigger)
commandMap[trigger] = c.getCommandCompletionItem(cmd, space) commandMap[trigger] = c.getCommandCompletionItem(cmd, space)
} }
} }
// Find fuzzy matches
matches := fuzzy.RankFindFold(query, commandNames) matches := fuzzy.RankFindFold(query, commandNames)
// Sort by score (best matches first)
sort.Sort(matches) sort.Sort(matches)
// Convert matches to completion items, deduplicating by command name // Convert matches to completion items, deduplicating by command name
+12 -12
View File
@@ -1,28 +1,28 @@
package chat package chat
import ( import (
"crypto/sha256"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"hash/fnv"
"sync" "sync"
) )
// MessageCache caches rendered messages to avoid re-rendering // PartCache caches rendered messages to avoid re-rendering
type MessageCache struct { type PartCache struct {
mu sync.RWMutex mu sync.RWMutex
cache map[string]string cache map[string]string
} }
// NewMessageCache creates a new message cache // NewPartCache creates a new message cache
func NewMessageCache() *MessageCache { func NewPartCache() *PartCache {
return &MessageCache{ return &PartCache{
cache: make(map[string]string), cache: make(map[string]string),
} }
} }
// generateKey creates a unique key for a message based on its content and rendering parameters // generateKey creates a unique key for a message based on its content and rendering parameters
func (c *MessageCache) GenerateKey(params ...any) string { func (c *PartCache) GenerateKey(params ...any) string {
h := sha256.New() h := fnv.New64a()
for _, param := range params { for _, param := range params {
h.Write(fmt.Appendf(nil, ":%v", param)) h.Write(fmt.Appendf(nil, ":%v", param))
} }
@@ -30,7 +30,7 @@ func (c *MessageCache) GenerateKey(params ...any) string {
} }
// Get retrieves a cached rendered message // Get retrieves a cached rendered message
func (c *MessageCache) Get(key string) (string, bool) { func (c *PartCache) Get(key string) (string, bool) {
c.mu.RLock() c.mu.RLock()
defer c.mu.RUnlock() defer c.mu.RUnlock()
@@ -39,14 +39,14 @@ func (c *MessageCache) Get(key string) (string, bool) {
} }
// Set stores a rendered message in the cache // Set stores a rendered message in the cache
func (c *MessageCache) Set(key string, content string) { func (c *PartCache) Set(key string, content string) {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
c.cache[key] = content c.cache[key] = content
} }
// Clear removes all entries from the cache // Clear removes all entries from the cache
func (c *MessageCache) Clear() { func (c *PartCache) Clear() {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
@@ -54,7 +54,7 @@ func (c *MessageCache) Clear() {
} }
// Size returns the number of cached entries // Size returns the number of cached entries
func (c *MessageCache) Size() int { func (c *PartCache) Size() int {
c.mu.RLock() c.mu.RLock()
defer c.mu.RUnlock() defer c.mu.RUnlock()
@@ -27,8 +27,8 @@ import (
type EditorComponent interface { type EditorComponent interface {
tea.Model tea.Model
View(width int) string tea.ViewModel
Content(width int) string Content() string
Lines() int Lines() int
Value() string Value() string
Length() int Length() int
@@ -46,6 +46,7 @@ type EditorComponent interface {
type editorComponent struct { type editorComponent struct {
app *app.App app *app.App
width int
textarea textarea.Model textarea textarea.Model
spinner spinner.Model spinner spinner.Model
interruptKeyInDebounce bool interruptKeyInDebounce bool
@@ -61,6 +62,12 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd var cmd tea.Cmd
switch msg := msg.(type) { switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.width = min(msg.Width-4, app.MAX_CONTAINER_WIDTH)
if m.app.Config.Layout == opencode.LayoutConfigStretch {
m.width = msg.Width - 4
}
return m, nil
case spinner.TickMsg: case spinner.TickMsg:
m.spinner, cmd = m.spinner.Update(msg) m.spinner, cmd = m.spinner.Update(msg)
return m, cmd return m, cmd
@@ -227,7 +234,7 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, tea.Batch(cmds...) return m, tea.Batch(cmds...)
} }
func (m *editorComponent) Content(width int) string { func (m *editorComponent) Content() string {
t := theme.CurrentTheme() t := theme.CurrentTheme()
base := styles.NewStyle().Foreground(t.Text()).Background(t.Background()).Render base := styles.NewStyle().Foreground(t.Text()).Background(t.Background()).Render
muted := styles.NewStyle().Foreground(t.TextMuted()).Background(t.Background()).Render muted := styles.NewStyle().Foreground(t.TextMuted()).Background(t.Background()).Render
@@ -236,7 +243,7 @@ func (m *editorComponent) Content(width int) string {
Bold(true) Bold(true)
prompt := promptStyle.Render(">") prompt := promptStyle.Render(">")
m.textarea.SetWidth(width - 6) m.textarea.SetWidth(m.width - 6)
textarea := lipgloss.JoinHorizontal( textarea := lipgloss.JoinHorizontal(
lipgloss.Top, lipgloss.Top,
prompt, prompt,
@@ -248,7 +255,7 @@ func (m *editorComponent) Content(width int) string {
} }
textarea = styles.NewStyle(). textarea = styles.NewStyle().
Background(t.BackgroundElement()). Background(t.BackgroundElement()).
Width(width). Width(m.width).
PaddingTop(1). PaddingTop(1).
PaddingBottom(1). PaddingBottom(1).
BorderStyle(lipgloss.ThickBorder()). BorderStyle(lipgloss.ThickBorder()).
@@ -284,7 +291,7 @@ func (m *editorComponent) Content(width int) string {
model = muted(m.app.Provider.Name) + base(" "+m.app.Model.Name) model = muted(m.app.Provider.Name) + base(" "+m.app.Model.Name)
} }
space := width - 2 - lipgloss.Width(model) - lipgloss.Width(hint) space := m.width - 2 - lipgloss.Width(model) - lipgloss.Width(hint)
spacer := styles.NewStyle().Background(t.Background()).Width(space).Render("") spacer := styles.NewStyle().Background(t.Background()).Width(space).Render("")
info := hint + spacer + model info := hint + spacer + model
@@ -294,10 +301,10 @@ func (m *editorComponent) Content(width int) string {
return content return content
} }
func (m *editorComponent) View(width int) string { func (m *editorComponent) View() string {
if m.Lines() > 1 { if m.Lines() > 1 {
return lipgloss.Place( return lipgloss.Place(
width, m.width,
5, 5,
lipgloss.Center, lipgloss.Center,
lipgloss.Center, lipgloss.Center,
@@ -305,7 +312,7 @@ func (m *editorComponent) View(width int) string {
styles.WhitespaceStyle(theme.CurrentTheme().Background()), styles.WhitespaceStyle(theme.CurrentTheme().Background()),
) )
} }
return m.Content(width) return m.Content()
} }
func (m *editorComponent) Focused() bool { func (m *editorComponent) Focused() bool {
@@ -337,6 +344,12 @@ func (m *editorComponent) Submit() (tea.Model, tea.Cmd) {
if value == "" { if value == "" {
return m, nil return m, nil
} }
switch value {
case "exit", "quit", "q", ":q":
return m, tea.Quit
}
if len(value) > 0 && value[len(value)-1] == '\\' { if len(value) > 0 && value[len(value)-1] == '\\' {
// If the last character is a backslash, remove it and add a newline // If the last character is a backslash, remove it and add a newline
m.textarea.ReplaceRange(len(value)-1, len(value), "") m.textarea.ReplaceRange(len(value)-1, len(value), "")
@@ -9,11 +9,11 @@ import (
"github.com/charmbracelet/lipgloss/v2" "github.com/charmbracelet/lipgloss/v2"
"github.com/charmbracelet/lipgloss/v2/compat" "github.com/charmbracelet/lipgloss/v2/compat"
"github.com/charmbracelet/x/ansi"
"github.com/muesli/reflow/truncate"
"github.com/sst/opencode-sdk-go" "github.com/sst/opencode-sdk-go"
"github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/app"
"github.com/sst/opencode/internal/commands"
"github.com/sst/opencode/internal/components/diff" "github.com/sst/opencode/internal/components/diff"
"github.com/sst/opencode/internal/layout"
"github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/styles"
"github.com/sst/opencode/internal/theme" "github.com/sst/opencode/internal/theme"
"github.com/sst/opencode/internal/util" "github.com/sst/opencode/internal/util"
@@ -109,7 +109,6 @@ func WithPaddingBottom(padding int) renderingOption {
func renderContentBlock( func renderContentBlock(
app *app.App, app *app.App,
content string, content string,
highlight bool,
width int, width int,
options ...renderingOption, options ...renderingOption,
) string { ) string {
@@ -158,18 +157,6 @@ func renderContentBlock(
BorderRightBackground(t.Background()) BorderRightBackground(t.Background())
} }
if highlight {
style = style.
BorderLeftForeground(borderColor).
BorderRightForeground(borderColor)
}
}
if highlight {
style = style.
Foreground(t.Text()).
Background(t.BackgroundElement()).
Bold(true)
} }
content = style.Render(content) content = style.Render(content)
@@ -184,32 +171,6 @@ func renderContentBlock(
} }
} }
if highlight {
copy := app.Key(commands.MessagesCopyCommand)
// revert := app.Key(commands.MessagesRevertCommand)
background := t.Background()
header := layout.Render(
layout.FlexOptions{
Background: &background,
Direction: layout.Row,
Justify: layout.JustifyCenter,
Align: layout.AlignStretch,
Width: width - 2,
Gap: 5,
},
layout.FlexItem{
View: copy,
},
// layout.FlexItem{
// View: revert,
// },
)
header = styles.NewStyle().Background(t.Background()).Padding(0, 1).Render(header)
content = "\n\n\n" + header + "\n\n" + content + "\n\n\n"
}
return content return content
} }
@@ -219,7 +180,6 @@ func renderText(
text string, text string,
author string, author string,
showToolDetails bool, showToolDetails bool,
highlight bool,
width int, width int,
extra string, extra string,
toolCalls ...opencode.ToolPart, toolCalls ...opencode.ToolPart,
@@ -228,9 +188,6 @@ func renderText(
var ts time.Time var ts time.Time
backgroundColor := t.BackgroundPanel() backgroundColor := t.BackgroundPanel()
if highlight {
backgroundColor = t.BackgroundElement()
}
var content string var content string
switch casted := message.(type) { switch casted := message.(type) {
case opencode.AssistantMessage: case opencode.AssistantMessage:
@@ -238,8 +195,18 @@ func renderText(
content = util.ToMarkdown(text, width, backgroundColor) content = util.ToMarkdown(text, width, backgroundColor)
case opencode.UserMessage: case opencode.UserMessage:
ts = time.UnixMilli(int64(casted.Time.Created)) ts = time.UnixMilli(int64(casted.Time.Created))
messageStyle := styles.NewStyle().Background(backgroundColor).Width(width - 6) base := styles.NewStyle().Foreground(t.Text()).Background(backgroundColor)
content = messageStyle.Render(text) words := strings.Fields(text)
for i, word := range words {
if strings.HasPrefix(word, "@") {
words[i] = base.Foreground(t.Secondary()).Render(word + " ")
} else {
words[i] = base.Render(word + " ")
}
}
text = strings.Join(words, "")
text = ansi.WordwrapWc(text, width-6, " -")
content = base.Width(width - 6).Render(text)
} }
timestamp := ts. timestamp := ts.
@@ -277,7 +244,6 @@ func renderText(
return renderContentBlock( return renderContentBlock(
app, app,
content, content,
highlight,
width, width,
WithTextColor(t.Text()), WithTextColor(t.Text()),
WithBorderColorRight(t.Secondary()), WithBorderColorRight(t.Secondary()),
@@ -286,7 +252,6 @@ func renderText(
return renderContentBlock( return renderContentBlock(
app, app,
content, content,
highlight,
width, width,
WithBorderColor(t.Accent()), WithBorderColor(t.Accent()),
) )
@@ -297,7 +262,6 @@ func renderText(
func renderToolDetails( func renderToolDetails(
app *app.App, app *app.App,
toolCall opencode.ToolPart, toolCall opencode.ToolPart,
highlight bool,
width int, width int,
) string { ) string {
ignoredTools := []string{"todoread"} ignoredTools := []string{"todoread"}
@@ -307,7 +271,7 @@ func renderToolDetails(
if toolCall.State.Status == opencode.ToolPartStateStatusPending { if toolCall.State.Status == opencode.ToolPartStateStatusPending {
title := renderToolTitle(toolCall, width) title := renderToolTitle(toolCall, width)
return renderContentBlock(app, title, highlight, width) return renderContentBlock(app, title, width)
} }
var result *string var result *string
@@ -332,10 +296,7 @@ func renderToolDetails(
t := theme.CurrentTheme() t := theme.CurrentTheme()
backgroundColor := t.BackgroundPanel() backgroundColor := t.BackgroundPanel()
borderColor := t.BackgroundPanel() borderColor := t.BackgroundPanel()
if highlight { defaultStyle := styles.NewStyle().Background(backgroundColor).Width(width - 6).Render
backgroundColor = t.BackgroundElement()
borderColor = t.BorderActive()
}
if toolCall.State.Metadata != nil { if toolCall.State.Metadata != nil {
metadata := toolCall.State.Metadata.(map[string]any) metadata := toolCall.State.Metadata.(map[string]any)
@@ -359,22 +320,27 @@ func renderToolDetails(
if diffField != nil { if diffField != nil {
patch := diffField.(string) patch := diffField.(string)
var formattedDiff string var formattedDiff string
if width < 120 {
formattedDiff, _ = diff.FormatUnifiedDiff( formattedDiff, _ = diff.FormatUnifiedDiff(
filename, filename,
patch, patch,
diff.WithWidth(width-2), diff.WithWidth(width-2),
) )
} else {
formattedDiff, _ = diff.FormatDiff(
filename,
patch,
diff.WithWidth(width-2),
)
}
body = strings.TrimSpace(formattedDiff) body = strings.TrimSpace(formattedDiff)
style := styles.NewStyle(). style := styles.NewStyle().
Background(backgroundColor). Background(backgroundColor).
Foreground(t.TextMuted()). Foreground(t.TextMuted()).
Padding(1, 2). Padding(1, 2).
Width(width - 4) Width(width - 4)
if highlight {
style = style.Foreground(t.Text()).Bold(true)
}
if diagnostics := renderDiagnostics(metadata, filename); diagnostics != "" { if diagnostics := renderDiagnostics(metadata, filename, backgroundColor, width-6); diagnostics != "" {
diagnostics = style.Render(diagnostics) diagnostics = style.Render(diagnostics)
body += "\n" + diagnostics body += "\n" + diagnostics
} }
@@ -385,7 +351,6 @@ func renderToolDetails(
content = renderContentBlock( content = renderContentBlock(
app, app,
content, content,
highlight,
width, width,
WithPadding(0), WithPadding(0),
WithBorderColor(borderColor), WithBorderColor(borderColor),
@@ -397,7 +362,7 @@ func renderToolDetails(
if filename, ok := toolInputMap["filePath"].(string); ok { if filename, ok := toolInputMap["filePath"].(string); ok {
if content, ok := toolInputMap["content"].(string); ok { if content, ok := toolInputMap["content"].(string); ok {
body = util.RenderFile(filename, content, width) body = util.RenderFile(filename, content, width)
if diagnostics := renderDiagnostics(metadata, filename); diagnostics != "" { if diagnostics := renderDiagnostics(metadata, filename, backgroundColor, width-4); diagnostics != "" {
body += "\n\n" + diagnostics body += "\n\n" + diagnostics
} }
} }
@@ -453,7 +418,7 @@ func renderToolDetails(
} }
body = strings.Join(steps, "\n") body = strings.Join(steps, "\n")
} }
body = styles.NewStyle().Width(width - 6).Render(body) body = defaultStyle(body)
default: default:
if result == nil { if result == nil {
empty := "" empty := ""
@@ -461,7 +426,7 @@ func renderToolDetails(
} }
body = *result body = *result
body = util.TruncateHeight(body, 10) body = util.TruncateHeight(body, 10)
body = styles.NewStyle().Width(width - 6).Render(body) body = defaultStyle(body)
} }
} }
@@ -481,12 +446,16 @@ func renderToolDetails(
if body == "" && error == "" && result != nil { if body == "" && error == "" && result != nil {
body = *result body = *result
body = util.TruncateHeight(body, 10) body = util.TruncateHeight(body, 10)
body = styles.NewStyle().Width(width - 6).Render(body) body = defaultStyle(body)
}
if body == "" {
body = defaultStyle("")
} }
title := renderToolTitle(toolCall, width) title := renderToolTitle(toolCall, width)
content := title + "\n\n" + body content := title + "\n\n" + body
return renderContentBlock(app, content, highlight, width, WithBorderColor(borderColor)) return renderContentBlock(app, content, width, WithBorderColor(borderColor))
} }
func renderToolName(name string) string { func renderToolName(name string) string {
@@ -591,6 +560,8 @@ func renderToolTitle(
toolName := renderToolName(toolCall.Tool) toolName := renderToolName(toolCall.Tool)
title = fmt.Sprintf("%s %s", toolName, toolArgs) title = fmt.Sprintf("%s %s", toolName, toolArgs)
} }
title = truncate.StringWithTail(title, uint(width-6), "...")
return title return title
} }
@@ -668,7 +639,12 @@ type Diagnostic struct {
} }
// renderDiagnostics formats LSP diagnostics for display in the TUI // renderDiagnostics formats LSP diagnostics for display in the TUI
func renderDiagnostics(metadata map[string]any, filePath string) string { func renderDiagnostics(
metadata map[string]any,
filePath string,
backgroundColor compat.AdaptiveColor,
width int,
) string {
if diagnosticsData, ok := metadata["diagnostics"].(map[string]any); ok { if diagnosticsData, ok := metadata["diagnostics"].(map[string]any); ok {
if fileDiagnostics, ok := diagnosticsData[filePath].([]any); ok { if fileDiagnostics, ok := diagnosticsData[filePath].([]any); ok {
var errorDiagnostics []string var errorDiagnostics []string
@@ -704,9 +680,15 @@ func renderDiagnostics(metadata map[string]any, filePath string) string {
var result strings.Builder var result strings.Builder
for _, diagnostic := range errorDiagnostics { for _, diagnostic := range errorDiagnostics {
if result.Len() > 0 { if result.Len() > 0 {
result.WriteString("\n") result.WriteString("\n\n")
} }
result.WriteString(styles.NewStyle().Foreground(t.Error()).Render(diagnostic)) diagnostic = ansi.WordwrapWc(diagnostic, width, " -")
result.WriteString(
styles.NewStyle().
Background(backgroundColor).
Foreground(t.Error()).
Render(diagnostic),
)
} }
return result.String() return result.String()
} }
+136 -130
View File
@@ -10,6 +10,7 @@ import (
"github.com/sst/opencode-sdk-go" "github.com/sst/opencode-sdk-go"
"github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/app"
"github.com/sst/opencode/internal/components/dialog" "github.com/sst/opencode/internal/components/dialog"
"github.com/sst/opencode/internal/components/toast"
"github.com/sst/opencode/internal/layout" "github.com/sst/opencode/internal/layout"
"github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/styles"
"github.com/sst/opencode/internal/theme" "github.com/sst/opencode/internal/theme"
@@ -18,37 +19,30 @@ import (
type MessagesComponent interface { type MessagesComponent interface {
tea.Model tea.Model
View(width, height int) string tea.ViewModel
SetWidth(width int) tea.Cmd
PageUp() (tea.Model, tea.Cmd) PageUp() (tea.Model, tea.Cmd)
PageDown() (tea.Model, tea.Cmd) PageDown() (tea.Model, tea.Cmd)
HalfPageUp() (tea.Model, tea.Cmd) HalfPageUp() (tea.Model, tea.Cmd)
HalfPageDown() (tea.Model, tea.Cmd) HalfPageDown() (tea.Model, tea.Cmd)
First() (tea.Model, tea.Cmd)
Last() (tea.Model, tea.Cmd)
Previous() (tea.Model, tea.Cmd)
Next() (tea.Model, tea.Cmd)
ToolDetailsVisible() bool ToolDetailsVisible() bool
Selected() string GotoTop() (tea.Model, tea.Cmd)
GotoBottom() (tea.Model, tea.Cmd)
CopyLastMessage() (tea.Model, tea.Cmd)
} }
type messagesComponent struct { type messagesComponent struct {
width int width, height int
app *app.App app *app.App
header string
viewport viewport.Model viewport viewport.Model
cache *MessageCache cache *PartCache
rendering bool rendering bool
showToolDetails bool showToolDetails bool
tail bool tail bool
partCount int partCount int
lineCount int lineCount int
selectedPart int
selectedText string
} }
type renderFinishedMsg struct{} type renderFinishedMsg struct{}
type selectedMessagePartChangedMsg struct {
part int
}
type ToggleToolDetailsMsg struct{} type ToggleToolDetailsMsg struct{}
@@ -56,17 +50,23 @@ func (m *messagesComponent) Init() tea.Cmd {
return tea.Batch(m.viewport.Init()) return tea.Batch(m.viewport.Init())
} }
func (m *messagesComponent) Selected() string {
return m.selectedText
}
func (m *messagesComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (m *messagesComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmds []tea.Cmd var cmds []tea.Cmd
switch msg := msg.(type) { switch msg := msg.(type) {
case tea.WindowSizeMsg:
effectiveWidth := msg.Width - 4
// Clear cache on resize since width affects rendering
if m.width != effectiveWidth {
m.cache.Clear()
}
m.width = effectiveWidth
m.height = msg.Height - 7
m.viewport.SetWidth(m.width)
m.header = m.renderHeader()
return m, m.Reload()
case app.SendMsg: case app.SendMsg:
m.viewport.GotoBottom() m.viewport.GotoBottom()
m.tail = true m.tail = true
m.selectedPart = -1
return m, nil return m, nil
case app.OptimisticMessageAddedMsg: case app.OptimisticMessageAddedMsg:
m.tail = true m.tail = true
@@ -90,25 +90,21 @@ func (m *messagesComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if m.tail { if m.tail {
m.viewport.GotoBottom() m.viewport.GotoBottom()
} }
case selectedMessagePartChangedMsg:
return m, m.Reload()
case opencode.EventListResponseEventSessionUpdated: case opencode.EventListResponseEventSessionUpdated:
if msg.Properties.Info.ID == m.app.Session.ID { if msg.Properties.Info.ID == m.app.Session.ID {
m.renderView(m.width) m.header = m.renderHeader()
if m.tail {
m.viewport.GotoBottom()
}
} }
case opencode.EventListResponseEventMessageUpdated: case opencode.EventListResponseEventMessageUpdated:
if msg.Properties.Info.SessionID == m.app.Session.ID { if msg.Properties.Info.SessionID == m.app.Session.ID {
m.renderView(m.width) m.renderView()
if m.tail { if m.tail {
m.viewport.GotoBottom() m.viewport.GotoBottom()
} }
} }
case opencode.EventListResponseEventMessagePartUpdated: case opencode.EventListResponseEventMessagePartUpdated:
if msg.Properties.Part.SessionID == m.app.Session.ID { if msg.Properties.Part.SessionID == m.app.Session.ID {
m.renderView(m.width) m.renderView()
if m.tail { if m.tail {
m.viewport.GotoBottom() m.viewport.GotoBottom()
} }
@@ -123,10 +119,12 @@ func (m *messagesComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, tea.Batch(cmds...) return m, tea.Batch(cmds...)
} }
func (m *messagesComponent) renderView(width int) { func (m *messagesComponent) renderView() {
measure := util.Measure("messages.renderView") measure := util.Measure("messages.renderView")
defer measure("messageCount", len(m.app.Messages)) defer measure("messageCount", len(m.app.Messages))
m.header = m.renderHeader()
t := theme.CurrentTheme() t := theme.CurrentTheme()
blocks := make([]string, 0) blocks := make([]string, 0)
m.partCount = 0 m.partCount = 0
@@ -134,16 +132,23 @@ func (m *messagesComponent) renderView(width int) {
orphanedToolCalls := make([]opencode.ToolPart, 0) orphanedToolCalls := make([]opencode.ToolPart, 0)
width := min(m.width, app.MAX_CONTAINER_WIDTH)
if m.app.Config.Layout == opencode.LayoutConfigStretch {
width = m.width
}
for _, message := range m.app.Messages { for _, message := range m.app.Messages {
var content string var content string
var cached bool var cached bool
switch casted := message.Info.(type) { switch casted := message.Info.(type) {
case opencode.UserMessage: case opencode.UserMessage:
userLoop:
for partIndex, part := range message.Parts { for partIndex, part := range message.Parts {
switch part := part.(type) { switch part := part.(type) {
case opencode.TextPart: case opencode.TextPart:
if part.Synthetic {
continue
}
remainingParts := message.Parts[partIndex+1:] remainingParts := message.Parts[partIndex+1:]
fileParts := make([]opencode.FilePart, 0) fileParts := make([]opencode.FilePart, 0)
for _, part := range remainingParts { for _, part := range remainingParts {
@@ -183,7 +188,7 @@ func (m *messagesComponent) renderView(width int) {
flexItems..., flexItems...,
) )
key := m.cache.GenerateKey(casted.ID, part.Text, width, m.selectedPart == m.partCount, files) key := m.cache.GenerateKey(casted.ID, part.Text, width, files)
content, cached = m.cache.Get(key) content, cached = m.cache.Get(key)
if !cached { if !cached {
content = renderText( content = renderText(
@@ -192,18 +197,22 @@ func (m *messagesComponent) renderView(width int) {
part.Text, part.Text,
m.app.Config.Username, m.app.Config.Username,
m.showToolDetails, m.showToolDetails,
m.partCount == m.selectedPart,
width, width,
files, files,
) )
content = lipgloss.PlaceHorizontal(
m.width,
lipgloss.Center,
content,
styles.WhitespaceStyle(t.Background()),
)
m.cache.Set(key, content) m.cache.Set(key, content)
} }
if content != "" { if content != "" {
m = m.updateSelected(content, part.Text) m.partCount++
m.lineCount += lipgloss.Height(content) + 1
blocks = append(blocks, content) blocks = append(blocks, content)
} }
// Only render the first text part
break userLoop
} }
} }
@@ -236,7 +245,7 @@ func (m *messagesComponent) renderView(width int) {
remaining = false remaining = false
case opencode.ToolPart: case opencode.ToolPart:
toolCallParts = append(toolCallParts, part) toolCallParts = append(toolCallParts, part)
if part.State.Status != opencode.ToolPartStateStatusCompleted || part.State.Status != opencode.ToolPartStateStatusError { if part.State.Status != opencode.ToolPartStateStatusCompleted && part.State.Status != opencode.ToolPartStateStatusError {
// i don't think there's a case where a tool call isn't in result state // i don't think there's a case where a tool call isn't in result state
// and the message time is 0, but just in case // and the message time is 0, but just in case
finished = false finished = false
@@ -245,7 +254,7 @@ func (m *messagesComponent) renderView(width int) {
} }
if finished { if finished {
key := m.cache.GenerateKey(casted.ID, part.Text, width, m.showToolDetails, m.selectedPart == m.partCount) key := m.cache.GenerateKey(casted.ID, part.Text, width, m.showToolDetails)
content, cached = m.cache.Get(key) content, cached = m.cache.Get(key)
if !cached { if !cached {
content = renderText( content = renderText(
@@ -254,11 +263,16 @@ func (m *messagesComponent) renderView(width int) {
part.Text, part.Text,
casted.ModelID, casted.ModelID,
m.showToolDetails, m.showToolDetails,
m.partCount == m.selectedPart,
width, width,
"", "",
toolCallParts..., toolCallParts...,
) )
content = lipgloss.PlaceHorizontal(
m.width,
lipgloss.Center,
content,
styles.WhitespaceStyle(t.Background()),
)
m.cache.Set(key, content) m.cache.Set(key, content)
} }
} else { } else {
@@ -268,14 +282,20 @@ func (m *messagesComponent) renderView(width int) {
part.Text, part.Text,
casted.ModelID, casted.ModelID,
m.showToolDetails, m.showToolDetails,
m.partCount == m.selectedPart,
width, width,
"", "",
toolCallParts..., toolCallParts...,
) )
content = lipgloss.PlaceHorizontal(
m.width,
lipgloss.Center,
content,
styles.WhitespaceStyle(t.Background()),
)
} }
if content != "" { if content != "" {
m = m.updateSelected(content, part.Text) m.partCount++
m.lineCount += lipgloss.Height(content) + 1
blocks = append(blocks, content) blocks = append(blocks, content)
} }
case opencode.ToolPart: case opencode.ToolPart:
@@ -286,21 +306,32 @@ func (m *messagesComponent) renderView(width int) {
continue continue
} }
width := width
if m.app.Config.Layout == opencode.LayoutConfigAuto &&
part.Tool == "edit" &&
part.State.Error == "" {
width = min(m.width, app.EDIT_DIFF_MAX_WIDTH)
}
if part.State.Status == opencode.ToolPartStateStatusCompleted || part.State.Status == opencode.ToolPartStateStatusError { if part.State.Status == opencode.ToolPartStateStatusCompleted || part.State.Status == opencode.ToolPartStateStatusError {
key := m.cache.GenerateKey(casted.ID, key := m.cache.GenerateKey(casted.ID,
part.ID, part.ID,
m.showToolDetails, m.showToolDetails,
width, width,
m.partCount == m.selectedPart,
) )
content, cached = m.cache.Get(key) content, cached = m.cache.Get(key)
if !cached { if !cached {
content = renderToolDetails( content = renderToolDetails(
m.app, m.app,
part, part,
m.partCount == m.selectedPart,
width, width,
) )
content = lipgloss.PlaceHorizontal(
m.width,
lipgloss.Center,
content,
styles.WhitespaceStyle(t.Background()),
)
m.cache.Set(key, content) m.cache.Set(key, content)
} }
} else { } else {
@@ -308,12 +339,18 @@ func (m *messagesComponent) renderView(width int) {
content = renderToolDetails( content = renderToolDetails(
m.app, m.app,
part, part,
m.partCount == m.selectedPart,
width, width,
) )
content = lipgloss.PlaceHorizontal(
m.width,
lipgloss.Center,
content,
styles.WhitespaceStyle(t.Background()),
)
} }
if content != "" { if content != "" {
m = m.updateSelected(content, "") m.partCount++
m.lineCount += lipgloss.Height(content) + 1
blocks = append(blocks, content) blocks = append(blocks, content)
} }
} }
@@ -340,7 +377,6 @@ func (m *messagesComponent) renderView(width int) {
error = renderContentBlock( error = renderContentBlock(
m.app, m.app,
error, error,
false,
width, width,
WithBorderColor(t.Error()), WithBorderColor(t.Error()),
) )
@@ -349,35 +385,27 @@ func (m *messagesComponent) renderView(width int) {
} }
} }
m.viewport.SetHeight(m.height - lipgloss.Height(m.header))
m.viewport.SetContent("\n" + strings.Join(blocks, "\n\n")) m.viewport.SetContent("\n" + strings.Join(blocks, "\n\n"))
if m.selectedPart == m.partCount {
m.viewport.GotoBottom()
}
} }
func (m *messagesComponent) updateSelected(content string, selectedText string) *messagesComponent { func (m *messagesComponent) renderHeader() string {
if m.selectedPart == m.partCount {
m.viewport.SetYOffset(m.lineCount - (m.viewport.Height() / 2) + 4)
m.selectedText = selectedText
}
m.partCount++
m.lineCount += lipgloss.Height(content) + 1
return m
}
func (m *messagesComponent) header(width int) string {
if m.app.Session.ID == "" { if m.app.Session.ID == "" {
return "" return ""
} }
headerWidth := min(m.width, app.MAX_CONTAINER_WIDTH)
if m.app.Config.Layout == opencode.LayoutConfigStretch {
headerWidth = m.width
}
t := theme.CurrentTheme() t := theme.CurrentTheme()
base := styles.NewStyle().Foreground(t.Text()).Background(t.Background()).Render base := styles.NewStyle().Foreground(t.Text()).Background(t.Background()).Render
muted := styles.NewStyle().Foreground(t.TextMuted()).Background(t.Background()).Render muted := styles.NewStyle().Foreground(t.TextMuted()).Background(t.Background()).Render
headerLines := []string{} headerLines := []string{}
headerLines = append( headerLines = append(
headerLines, headerLines,
util.ToMarkdown("# "+m.app.Session.Title, width-6, t.Background()), util.ToMarkdown("# "+m.app.Session.Title, headerWidth-6, t.Background()),
) )
share := "" share := ""
@@ -426,7 +454,7 @@ func (m *messagesComponent) header(width int) string {
Direction: layout.Row, Direction: layout.Row,
Justify: layout.JustifySpaceBetween, Justify: layout.JustifySpaceBetween,
Align: layout.AlignStretch, Align: layout.AlignStretch,
Width: width - 6, Width: headerWidth - 6,
}, },
layout.FlexItem{ layout.FlexItem{
View: share, View: share,
@@ -437,12 +465,10 @@ func (m *messagesComponent) header(width int) string {
) )
headerLines = append(headerLines, share) headerLines = append(headerLines, share)
header := strings.Join(headerLines, "\n") header := strings.Join(headerLines, "\n")
header = styles.NewStyle(). header = styles.NewStyle().
Background(t.Background()). Background(t.Background()).
Width(width). Width(headerWidth).
PaddingLeft(2). PaddingLeft(2).
PaddingRight(2). PaddingRight(2).
BorderLeft(true). BorderLeft(true).
@@ -451,6 +477,12 @@ func (m *messagesComponent) header(width int) string {
BorderForeground(t.BackgroundElement()). BorderForeground(t.BackgroundElement()).
BorderStyle(lipgloss.ThickBorder()). BorderStyle(lipgloss.ThickBorder()).
Render(header) Render(header)
header = lipgloss.PlaceHorizontal(
m.width,
lipgloss.Center,
header,
styles.WhitespaceStyle(t.Background()),
)
return "\n" + header + "\n" return "\n" + header + "\n"
} }
@@ -480,7 +512,10 @@ func formatTokensAndCost(
formattedTokens = strings.Replace(formattedTokens, ".0M", "M", 1) formattedTokens = strings.Replace(formattedTokens, ".0M", "M", 1)
} }
percentage := (float64(tokens) / float64(contextWindow)) * 100 percentage := 0.0
if contextWindow > 0 {
percentage = (float64(tokens) / float64(contextWindow)) * 100
}
if isSubscriptionModel { if isSubscriptionModel {
return fmt.Sprintf( return fmt.Sprintf(
@@ -499,44 +534,27 @@ func formatTokensAndCost(
) )
} }
func (m *messagesComponent) View(width, height int) string { func (m *messagesComponent) View() string {
t := theme.CurrentTheme() t := theme.CurrentTheme()
if m.rendering { if m.rendering {
return lipgloss.Place( return lipgloss.Place(
width, m.width,
height, m.height,
lipgloss.Center, lipgloss.Center,
lipgloss.Center, lipgloss.Center,
styles.NewStyle().Background(t.Background()).Render(""), styles.NewStyle().Background(t.Background()).Render(""),
styles.WhitespaceStyle(t.Background()), styles.WhitespaceStyle(t.Background()),
) )
} }
header := m.header(width)
m.viewport.SetWidth(width)
m.viewport.SetHeight(height - lipgloss.Height(header))
return styles.NewStyle(). return styles.NewStyle().
Background(t.Background()). Background(t.Background()).
Render(header + "\n" + m.viewport.View()) Render(m.header + "\n" + m.viewport.View())
}
func (m *messagesComponent) SetWidth(width int) tea.Cmd {
if m.width == width {
return nil
}
// Clear cache on resize since width affects rendering
if m.width != width {
m.cache.Clear()
}
m.width = width
m.viewport.SetWidth(width)
m.renderView(width)
return nil
} }
func (m *messagesComponent) Reload() tea.Cmd { func (m *messagesComponent) Reload() tea.Cmd {
return func() tea.Msg { return func() tea.Msg {
m.renderView(m.width) m.renderView()
return renderFinishedMsg{} return renderFinishedMsg{}
} }
} }
@@ -561,51 +579,40 @@ func (m *messagesComponent) HalfPageDown() (tea.Model, tea.Cmd) {
return m, nil return m, nil
} }
func (m *messagesComponent) Previous() (tea.Model, tea.Cmd) {
m.tail = false
if m.selectedPart < 0 {
m.selectedPart = m.partCount
}
m.selectedPart--
if m.selectedPart < 0 {
m.selectedPart = 0
}
return m, util.CmdHandler(selectedMessagePartChangedMsg{
part: m.selectedPart,
})
}
func (m *messagesComponent) Next() (tea.Model, tea.Cmd) {
m.tail = false
m.selectedPart++
if m.selectedPart >= m.partCount {
m.selectedPart = m.partCount
}
return m, util.CmdHandler(selectedMessagePartChangedMsg{
part: m.selectedPart,
})
}
func (m *messagesComponent) First() (tea.Model, tea.Cmd) {
m.selectedPart = 0
m.tail = false
return m, util.CmdHandler(selectedMessagePartChangedMsg{
part: m.selectedPart,
})
}
func (m *messagesComponent) Last() (tea.Model, tea.Cmd) {
m.selectedPart = m.partCount - 1
m.tail = true
return m, util.CmdHandler(selectedMessagePartChangedMsg{
part: m.selectedPart,
})
}
func (m *messagesComponent) ToolDetailsVisible() bool { func (m *messagesComponent) ToolDetailsVisible() bool {
return m.showToolDetails return m.showToolDetails
} }
func (m *messagesComponent) GotoTop() (tea.Model, tea.Cmd) {
m.viewport.GotoTop()
return m, nil
}
func (m *messagesComponent) GotoBottom() (tea.Model, tea.Cmd) {
m.viewport.GotoBottom()
return m, nil
}
func (m *messagesComponent) CopyLastMessage() (tea.Model, tea.Cmd) {
if len(m.app.Messages) == 0 {
return m, nil
}
lastMessage := m.app.Messages[len(m.app.Messages)-1]
var lastTextPart *opencode.TextPart
for _, part := range lastMessage.Parts {
if p, ok := part.(opencode.TextPart); ok {
lastTextPart = &p
}
}
if lastTextPart == nil {
return m, nil
}
var cmds []tea.Cmd
cmds = append(cmds, m.app.SetClipboard(lastTextPart.Text))
cmds = append(cmds, toast.NewSuccessToast("Message copied to clipboard"))
return m, tea.Batch(cmds...)
}
func NewMessagesComponent(app *app.App) MessagesComponent { func NewMessagesComponent(app *app.App) MessagesComponent {
vp := viewport.New() vp := viewport.New()
vp.KeyMap = viewport.KeyMap{} vp.KeyMap = viewport.KeyMap{}
@@ -614,8 +621,7 @@ func NewMessagesComponent(app *app.App) MessagesComponent {
app: app, app: app,
viewport: vp, viewport: vp,
showToolDetails: true, showToolDetails: true,
cache: NewMessageCache(), cache: NewPartCache(),
tail: true, tail: true,
selectedPart: -1,
} }
} }
@@ -56,7 +56,7 @@ var completionDialogKeys = completionDialogKeyMap{
key.WithKeys("tab", "enter", "right"), key.WithKeys("tab", "enter", "right"),
), ),
Cancel: key.NewBinding( Cancel: key.NewBinding(
key.WithKeys(" ", "esc", "backspace", "ctrl+h", "ctrl+c"), key.WithKeys("space", " ", "esc", "backspace", "ctrl+h", "ctrl+c"),
), ),
} }
@@ -85,7 +85,7 @@ func (c *completionDialogComponent) getAllCompletions(query string) tea.Cmd {
} }
// If there's a query, use fuzzy ranking to sort results // If there's a query, use fuzzy ranking to sort results
if query != "" && len(allItems) > 0 { if query != "" && len(allItems) > 0 && len(c.providers) > 1 {
t := theme.CurrentTheme() t := theme.CurrentTheme()
baseStyle := styles.NewStyle().Background(t.BackgroundElement()) baseStyle := styles.NewStyle().Background(t.BackgroundElement())
// Create a slice of display values for fuzzy matching // Create a slice of display values for fuzzy matching
@@ -94,10 +94,7 @@ func (c *completionDialogComponent) getAllCompletions(query string) tea.Cmd {
displayValues[i] = item.Display(baseStyle) displayValues[i] = item.Display(baseStyle)
} }
// Get fuzzy matches with ranking
matches := fuzzy.RankFindFold(query, displayValues) matches := fuzzy.RankFindFold(query, displayValues)
// Sort by score (best matches first)
sort.Sort(matches) sort.Sort(matches)
// Reorder items based on fuzzy ranking // Reorder items based on fuzzy ranking
@@ -38,6 +38,10 @@ const (
LineRemoved // Line removed from the old file LineRemoved // Line removed from the old file
) )
var (
ansiRegex = regexp.MustCompile(`\x1b(?:[@-Z\\-_]|\[[0-9?]*(?:;[0-9?]*)*[@-~])`)
)
// Segment represents a portion of a line for intra-line highlighting // Segment represents a portion of a line for intra-line highlighting
type Segment struct { type Segment struct {
Start int Start int
@@ -548,7 +552,6 @@ func createStyles(t theme.Theme) (removedLineStyle, addedLineStyle, contextLineS
// applyHighlighting applies intra-line highlighting to a piece of text // applyHighlighting applies intra-line highlighting to a piece of text
func applyHighlighting(content string, segments []Segment, segmentType LineType, highlightBg compat.AdaptiveColor) string { func applyHighlighting(content string, segments []Segment, segmentType LineType, highlightBg compat.AdaptiveColor) string {
// Find all ANSI sequences in the content // Find all ANSI sequences in the content
ansiRegex := regexp.MustCompile(`\x1b(?:[@-Z\\-_]|\[[0-9?]*(?:;[0-9?]*)*[@-~])`)
ansiMatches := ansiRegex.FindAllStringIndex(content, -1) ansiMatches := ansiRegex.FindAllStringIndex(content, -1)
// Build a mapping of visible character positions to their actual indices // Build a mapping of visible character positions to their actual indices
+5 -3
View File
@@ -15,6 +15,11 @@ import (
"github.com/sst/opencode/internal/util" "github.com/sst/opencode/internal/util"
) )
var (
// ANSI escape sequence regex
ansiRegex = regexp.MustCompile(`\x1b\[[0-9;]*m`)
)
// Split a string into lines, additionally returning the size of the widest line. // Split a string into lines, additionally returning the size of the widest line.
func getLines(s string) (lines []string, widest int) { func getLines(s string) (lines []string, widest int) {
lines = strings.Split(s, "\n") lines = strings.Split(s, "\n")
@@ -272,9 +277,6 @@ func combineStyles(bgStyle ansiStyle, fgColor *compat.AdaptiveColor) string {
// getStyleAtPosition extracts the active ANSI style at a given visual position // getStyleAtPosition extracts the active ANSI style at a given visual position
func getStyleAtPosition(s string, targetPos int) ansiStyle { func getStyleAtPosition(s string, targetPos int) ansiStyle {
// ANSI escape sequence regex
ansiRegex := regexp.MustCompile(`\x1b\[[0-9;]*m`)
visualPos := 0 visualPos := 0
currentStyle := ansiStyle{} currentStyle := ansiStyle{}
+136 -113
View File
@@ -2,6 +2,7 @@ package tui
import ( import (
"context" "context"
"fmt"
"log/slog" "log/slog"
"os" "os"
"os/exec" "os/exec"
@@ -55,7 +56,6 @@ const (
const interruptDebounceTimeout = 1 * time.Second const interruptDebounceTimeout = 1 * time.Second
const exitDebounceTimeout = 1 * time.Second const exitDebounceTimeout = 1 * time.Second
const fileViewerFullWidthCutoff = 160
type appModel struct { type appModel struct {
width, height int width, height int
@@ -76,10 +76,6 @@ type appModel struct {
exitKeyState ExitKeyState exitKeyState ExitKeyState
messagesRight bool messagesRight bool
fileViewer fileviewer.Model fileViewer fileviewer.Model
lastMouse tea.Mouse
fileViewerStart int
fileViewerEnd int
fileViewerHit bool
} }
func (a appModel) Init() tea.Cmd { func (a appModel) Init() tea.Cmd {
@@ -287,30 +283,16 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return a, cmd return a, cmd
case tea.MouseWheelMsg: case tea.MouseWheelMsg:
if a.modal != nil { if a.modal != nil {
return a, nil u, cmd := a.modal.Update(msg)
a.modal = u.(layout.Modal)
cmds = append(cmds, cmd)
return a, tea.Batch(cmds...)
} }
var cmd tea.Cmd
if a.fileViewerHit {
a.fileViewer, cmd = a.fileViewer.Update(msg)
cmds = append(cmds, cmd)
} else {
updated, cmd := a.messages.Update(msg) updated, cmd := a.messages.Update(msg)
a.messages = updated.(chat.MessagesComponent) a.messages = updated.(chat.MessagesComponent)
cmds = append(cmds, cmd) cmds = append(cmds, cmd)
}
return a, tea.Batch(cmds...) return a, tea.Batch(cmds...)
case tea.MouseMotionMsg:
a.lastMouse = msg.Mouse()
a.fileViewerHit = a.fileViewer.HasFile() &&
a.lastMouse.X > a.fileViewerStart &&
a.lastMouse.X < a.fileViewerEnd
case tea.MouseClickMsg:
a.lastMouse = msg.Mouse()
a.fileViewerHit = a.fileViewer.HasFile() &&
a.lastMouse.X > a.fileViewerStart &&
a.lastMouse.X < a.fileViewerEnd
case tea.BackgroundColorMsg: case tea.BackgroundColorMsg:
styles.Terminal = &styles.TerminalInfo{ styles.Terminal = &styles.TerminalInfo{
Background: msg.Color, Background: msg.Color,
@@ -457,14 +439,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case tea.WindowSizeMsg: case tea.WindowSizeMsg:
msg.Height -= 2 // Make space for the status bar msg.Height -= 2 // Make space for the status bar
a.width, a.height = msg.Width, msg.Height a.width, a.height = msg.Width, msg.Height
container := min(a.width, 104) container := min(a.width, app.MAX_CONTAINER_WIDTH)
if a.fileViewer.HasFile() {
if a.width < fileViewerFullWidthCutoff {
container = a.width
} else {
container = min(min(a.width, max(a.width/2, 50)), 104)
}
}
layout.Current = &layout.LayoutInfo{ layout.Current = &layout.LayoutInfo{
Viewport: layout.Dimensions{ Viewport: layout.Dimensions{
Width: a.width, Width: a.width,
@@ -474,21 +449,6 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
Width: container, Width: container,
}, },
} }
mainWidth := layout.Current.Container.Width
a.messages.SetWidth(mainWidth - 4)
sideWidth := a.width - mainWidth
if a.width < fileViewerFullWidthCutoff {
sideWidth = a.width
}
a.fileViewerStart = mainWidth
a.fileViewerEnd = a.fileViewerStart + sideWidth
if a.messagesRight {
a.fileViewerStart = 0
a.fileViewerEnd = sideWidth
}
a.fileViewer, cmd = a.fileViewer.SetSize(sideWidth, layout.Current.Viewport.Height)
cmds = append(cmds, cmd)
case app.SessionSelectedMsg: case app.SessionSelectedMsg:
messages, err := a.app.ListMessages(context.Background(), msg.ID) messages, err := a.app.ListMessages(context.Background(), msg.ID)
if err != nil { if err != nil {
@@ -568,48 +528,22 @@ func (a appModel) View() string {
t := theme.CurrentTheme() t := theme.CurrentTheme()
var mainLayout string var mainLayout string
mainWidth := layout.Current.Container.Width - 4
if a.app.Session.ID == "" { if a.app.Session.ID == "" {
mainLayout = a.home(mainWidth) mainLayout = a.home()
} else { } else {
mainLayout = a.chat(mainWidth) mainLayout = a.chat()
} }
mainLayout = styles.NewStyle(). mainLayout = styles.NewStyle().
Background(t.Background()). Background(t.Background()).
Padding(0, 2). Padding(0, 2).
Render(mainLayout) Render(mainLayout)
mainHeight := lipgloss.Height(mainLayout)
if a.fileViewer.HasFile() {
file := a.fileViewer.View()
baseStyle := styles.NewStyle().Background(t.BackgroundPanel())
sidePanel := baseStyle.Height(mainHeight).Render(file)
if a.width >= fileViewerFullWidthCutoff {
if a.messagesRight {
mainLayout = lipgloss.JoinHorizontal(
lipgloss.Top,
sidePanel,
mainLayout,
)
} else {
mainLayout = lipgloss.JoinHorizontal(
lipgloss.Top,
mainLayout,
sidePanel,
)
}
} else {
mainLayout = sidePanel
}
} else {
mainLayout = lipgloss.PlaceHorizontal( mainLayout = lipgloss.PlaceHorizontal(
a.width, a.width,
lipgloss.Center, lipgloss.Center,
mainLayout, mainLayout,
styles.WhitespaceStyle(t.Background()), styles.WhitespaceStyle(t.Background()),
) )
}
mainStyle := styles.NewStyle().Background(t.Background()) mainStyle := styles.NewStyle().Background(t.Background())
mainLayout = mainStyle.Render(mainLayout) mainLayout = mainStyle.Render(mainLayout)
@@ -645,8 +579,9 @@ func (a appModel) openFile(filepath string) (tea.Model, tea.Cmd) {
return a, cmd return a, cmd
} }
func (a appModel) home(width int) string { func (a appModel) home() string {
t := theme.CurrentTheme() t := theme.CurrentTheme()
effectiveWidth := a.width - 4
baseStyle := styles.NewStyle().Background(t.Background()) baseStyle := styles.NewStyle().Background(t.Background())
base := baseStyle.Render base := baseStyle.Render
muted := styles.NewStyle().Foreground(t.TextMuted()).Background(t.Background()).Render muted := styles.NewStyle().Foreground(t.TextMuted()).Background(t.Background()).Render
@@ -677,7 +612,7 @@ func (a appModel) home(width int) string {
logoAndVersion := strings.Join([]string{logo, version}, "\n") logoAndVersion := strings.Join([]string{logo, version}, "\n")
logoAndVersion = lipgloss.PlaceHorizontal( logoAndVersion = lipgloss.PlaceHorizontal(
width, effectiveWidth,
lipgloss.Center, lipgloss.Center,
logoAndVersion, logoAndVersion,
styles.WhitespaceStyle(t.Background()), styles.WhitespaceStyle(t.Background()),
@@ -688,7 +623,7 @@ func (a appModel) home(width int) string {
cmdcomp.WithLimit(6), cmdcomp.WithLimit(6),
) )
cmds := lipgloss.PlaceHorizontal( cmds := lipgloss.PlaceHorizontal(
width, effectiveWidth,
lipgloss.Center, lipgloss.Center,
commandsView.View(), commandsView.View(),
styles.WhitespaceStyle(t.Background()), styles.WhitespaceStyle(t.Background()),
@@ -700,19 +635,16 @@ func (a appModel) home(width int) string {
lines = append(lines, logoAndVersion) lines = append(lines, logoAndVersion)
lines = append(lines, "") lines = append(lines, "")
lines = append(lines, "") lines = append(lines, "")
// lines = append(lines, base("cwd ")+muted(cwd))
// lines = append(lines, base("config ")+muted(config))
// lines = append(lines, "")
lines = append(lines, cmds) lines = append(lines, cmds)
lines = append(lines, "") lines = append(lines, "")
lines = append(lines, "") lines = append(lines, "")
mainHeight := lipgloss.Height(strings.Join(lines, "\n")) mainHeight := lipgloss.Height(strings.Join(lines, "\n"))
editorWidth := min(width, 80) editorView := a.editor.View()
editorView := a.editor.View(editorWidth) editorWidth := lipgloss.Width(editorView)
editorView = lipgloss.PlaceHorizontal( editorView = lipgloss.PlaceHorizontal(
width, effectiveWidth,
lipgloss.Center, lipgloss.Center,
editorView, editorView,
styles.WhitespaceStyle(t.Background()), styles.WhitespaceStyle(t.Background()),
@@ -722,7 +654,7 @@ func (a appModel) home(width int) string {
editorLines := a.editor.Lines() editorLines := a.editor.Lines()
mainLayout := lipgloss.Place( mainLayout := lipgloss.Place(
width, effectiveWidth,
a.height, a.height,
lipgloss.Center, lipgloss.Center,
lipgloss.Center, lipgloss.Center,
@@ -730,14 +662,14 @@ func (a appModel) home(width int) string {
styles.WhitespaceStyle(t.Background()), styles.WhitespaceStyle(t.Background()),
) )
editorX := (width - editorWidth) / 2 editorX := (effectiveWidth - editorWidth) / 2
editorY := (a.height / 2) + (mainHeight / 2) - 2 editorY := (a.height / 2) + (mainHeight / 2) - 2
if editorLines > 1 { if editorLines > 1 {
mainLayout = layout.PlaceOverlay( mainLayout = layout.PlaceOverlay(
editorX, editorX,
editorY, editorY,
a.editor.Content(editorWidth), a.editor.Content(),
mainLayout, mainLayout,
) )
} }
@@ -758,23 +690,31 @@ func (a appModel) home(width int) string {
return mainLayout return mainLayout
} }
func (a appModel) chat(width int) string { func (a appModel) chat() string {
editorView := a.editor.View(width) effectiveWidth := a.width - 4
t := theme.CurrentTheme()
editorView := a.editor.View()
lines := a.editor.Lines() lines := a.editor.Lines()
messagesView := a.messages.View(width, a.height-5) messagesView := a.messages.View()
editorWidth := lipgloss.Width(editorView) editorWidth := lipgloss.Width(editorView)
editorHeight := max(lines, 5) editorHeight := max(lines, 5)
editorView = lipgloss.PlaceHorizontal(
effectiveWidth,
lipgloss.Center,
editorView,
styles.WhitespaceStyle(t.Background()),
)
mainLayout := messagesView + "\n" + editorView mainLayout := messagesView + "\n" + editorView
editorX := (a.width - editorWidth) / 2 editorX := (effectiveWidth - editorWidth) / 2
if lines > 1 { if lines > 1 {
editorY := a.height - editorHeight editorY := a.height - editorHeight
mainLayout = layout.PlaceOverlay( mainLayout = layout.PlaceOverlay(
editorX, editorX,
editorY, editorY,
a.editor.Content(width), a.editor.Content(),
mainLayout, mainLayout,
) )
} }
@@ -809,6 +749,10 @@ func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd)
updated, cmd := a.app.SwitchMode() updated, cmd := a.app.SwitchMode()
a.app = updated a.app = updated
cmds = append(cmds, cmd) cmds = append(cmds, cmd)
case commands.SwitchModeReverseCommand:
updated, cmd := a.app.SwitchModeReverse()
a.app = updated
cmds = append(cmds, cmd)
case commands.EditorOpenCommand: case commands.EditorOpenCommand:
if a.app.IsBusy() { if a.app.IsBusy() {
// status.Warn("Agent is working, please wait...") // status.Warn("Agent is working, please wait...")
@@ -900,6 +844,56 @@ func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd)
} }
// TODO: block until compaction is complete // TODO: block until compaction is complete
a.app.CompactSession(context.Background()) a.app.CompactSession(context.Background())
case commands.SessionExportCommand:
if a.app.Session.ID == "" {
return a, toast.NewErrorToast("No active session to export.")
}
// Use current conversation history
messages := a.app.Messages
if len(messages) == 0 {
return a, toast.NewInfoToast("No messages to export.")
}
// Format to Markdown
markdownContent := formatConversationToMarkdown(messages)
// Check if EDITOR is set
editor := os.Getenv("EDITOR")
if editor == "" {
return a, toast.NewErrorToast("No EDITOR set, can't open editor")
}
// Create and write to temp file
tmpfile, err := os.CreateTemp("", "conversation-*.md")
if err != nil {
slog.Error("Failed to create temp file", "error", err)
return a, toast.NewErrorToast("Failed to create temporary file.")
}
_, err = tmpfile.WriteString(markdownContent)
if err != nil {
slog.Error("Failed to write to temp file", "error", err)
tmpfile.Close()
os.Remove(tmpfile.Name())
return a, toast.NewErrorToast("Failed to write conversation to file.")
}
tmpfile.Close()
// Open in editor
c := exec.Command(editor, tmpfile.Name())
c.Stdin = os.Stdin
c.Stdout = os.Stdout
c.Stderr = os.Stderr
cmd = tea.ExecProcess(c, func(err error) tea.Msg {
if err != nil {
slog.Error("Failed to open editor for conversation", "error", err)
}
// Clean up the file after editor closes
os.Remove(tmpfile.Name())
return nil
})
cmds = append(cmds, cmd)
case commands.ToolDetailsCommand: case commands.ToolDetailsCommand:
message := "Tool details are now visible" message := "Tool details are now visible"
if a.messages.ToolDetailsVisible() { if a.messages.ToolDetailsVisible() {
@@ -913,11 +907,11 @@ func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd)
case commands.ThemeListCommand: case commands.ThemeListCommand:
themeDialog := dialog.NewThemeDialog() themeDialog := dialog.NewThemeDialog()
a.modal = themeDialog a.modal = themeDialog
case commands.FileListCommand: // case commands.FileListCommand:
a.editor.Blur() // a.editor.Blur()
findDialog := dialog.NewFindDialog(a.fileProvider) // findDialog := dialog.NewFindDialog(a.fileProvider)
cmds = append(cmds, findDialog.Init()) // cmds = append(cmds, findDialog.Init())
a.modal = findDialog // a.modal = findDialog
case commands.FileCloseCommand: case commands.FileCloseCommand:
a.fileViewer, cmd = a.fileViewer.Clear() a.fileViewer, cmd = a.fileViewer.Clear()
cmds = append(cmds, cmd) cmds = append(cmds, cmd)
@@ -950,11 +944,11 @@ func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd)
a.editor = updated.(chat.EditorComponent) a.editor = updated.(chat.EditorComponent)
cmds = append(cmds, cmd) cmds = append(cmds, cmd)
case commands.MessagesFirstCommand: case commands.MessagesFirstCommand:
updated, cmd := a.messages.First() updated, cmd := a.messages.GotoTop()
a.messages = updated.(chat.MessagesComponent) a.messages = updated.(chat.MessagesComponent)
cmds = append(cmds, cmd) cmds = append(cmds, cmd)
case commands.MessagesLastCommand: case commands.MessagesLastCommand:
updated, cmd := a.messages.Last() updated, cmd := a.messages.GotoBottom()
a.messages = updated.(chat.MessagesComponent) a.messages = updated.(chat.MessagesComponent)
cmds = append(cmds, cmd) cmds = append(cmds, cmd)
case commands.MessagesPageUpCommand: case commands.MessagesPageUpCommand:
@@ -993,26 +987,14 @@ func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd)
a.messages = updated.(chat.MessagesComponent) a.messages = updated.(chat.MessagesComponent)
cmds = append(cmds, cmd) cmds = append(cmds, cmd)
} }
case commands.MessagesPreviousCommand:
updated, cmd := a.messages.Previous()
a.messages = updated.(chat.MessagesComponent)
cmds = append(cmds, cmd)
case commands.MessagesNextCommand:
updated, cmd := a.messages.Next()
a.messages = updated.(chat.MessagesComponent)
cmds = append(cmds, cmd)
case commands.MessagesLayoutToggleCommand: case commands.MessagesLayoutToggleCommand:
a.messagesRight = !a.messagesRight a.messagesRight = !a.messagesRight
a.app.State.MessagesRight = a.messagesRight a.app.State.MessagesRight = a.messagesRight
a.app.SaveState() a.app.SaveState()
case commands.MessagesCopyCommand: case commands.MessagesCopyCommand:
selected := a.messages.Selected() updated, cmd := a.messages.CopyLastMessage()
if selected != "" { a.messages = updated.(chat.MessagesComponent)
cmd = a.app.SetClipboard(selected)
cmds = append(cmds, cmd) cmds = append(cmds, cmd)
cmd = toast.NewSuccessToast("Message copied to clipboard")
cmds = append(cmds, cmd)
}
case commands.MessagesRevertCommand: case commands.MessagesRevertCommand:
case commands.AppExitCommand: case commands.AppExitCommand:
return a, tea.Quit return a, tea.Quit
@@ -1055,3 +1037,44 @@ func NewModel(app *app.App) tea.Model {
return model return model
} }
func formatConversationToMarkdown(messages []app.Message) string {
var builder strings.Builder
builder.WriteString("# Conversation History\n\n")
for _, msg := range messages {
builder.WriteString("---\n\n")
var role string
var timestamp time.Time
switch info := msg.Info.(type) {
case opencode.UserMessage:
role = "User"
timestamp = time.UnixMilli(int64(info.Time.Created))
case opencode.AssistantMessage:
role = "Assistant"
timestamp = time.UnixMilli(int64(info.Time.Created))
default:
continue
}
builder.WriteString(
fmt.Sprintf("**%s** (*%s*)\n\n", role, timestamp.Format("2006-01-02 15:04:05")),
)
for _, part := range msg.Parts {
switch p := part.(type) {
case opencode.TextPart:
builder.WriteString(p.Text + "\n\n")
case opencode.FilePart:
builder.WriteString(fmt.Sprintf("[File: %s]\n\n", p.Filename))
case opencode.ToolPart:
builder.WriteString(fmt.Sprintf("[Tool: %s]\n\n", p.Tool))
}
}
}
return builder.String()
}
+3 -3
View File
@@ -1,4 +1,4 @@
configured_endpoints: 22 configured_endpoints: 22
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-7270b9e4859010d6680bcc92afcd6f7c679d80a2645f65d7097d19ce2e8cdc5a.yml openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-8792f91dd070f7b4ee671fc86e8a03976dc7fb6ee49f8c99ad989e1597003774.yml
openapi_spec_hash: 5fcbfaedebfea62c17c74437a9728b04 openapi_spec_hash: fe9dc3a074be560de0b97df9b5af2c1b
config_hash: 38041c37df28a1c4383718e6d148dd0a config_hash: b7f3d9742335715c458494988498b183
+9 -7
View File
@@ -21,6 +21,9 @@ Response Types:
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#App">App</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#App">App</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#LogLevel">LogLevel</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#LogLevel">LogLevel</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Mode">Mode</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Mode">Mode</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Model">Model</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Provider">Provider</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppProvidersResponse">AppProvidersResponse</a>
Methods: Methods:
@@ -28,6 +31,7 @@ Methods:
- <code title="post /app/init">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="post /app/init">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /log">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Log">Log</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppLogParams">AppLogParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="post /log">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Log">Log</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppLogParams">AppLogParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /mode">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Modes">Modes</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Mode">Mode</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="get /mode">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Modes">Modes</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Mode">Mode</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /config/providers">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Providers">Providers</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppProvidersResponse">AppProvidersResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
# Find # Find
@@ -59,17 +63,15 @@ Methods:
Response Types: Response Types:
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Config">Config</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Config">Config</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Keybinds">Keybinds</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#KeybindsConfig">KeybindsConfig</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#McpLocal">McpLocal</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#LayoutConfig">LayoutConfig</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#McpRemote">McpRemote</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#McpLocalConfig">McpLocalConfig</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Model">Model</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#McpRemoteConfig">McpRemoteConfig</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Provider">Provider</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ModeConfig">ModeConfig</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ConfigProvidersResponse">ConfigProvidersResponse</a>
Methods: Methods:
- <code title="get /config">client.Config.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ConfigService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Config">Config</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="get /config">client.Config.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ConfigService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Config">Config</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /config/providers">client.Config.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ConfigService.Providers">Providers</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ConfigProvidersResponse">ConfigProvidersResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
# Session # Session
+147
View File
@@ -63,6 +63,14 @@ func (r *AppService) Modes(ctx context.Context, opts ...option.RequestOption) (r
return return
} }
// List all providers
func (r *AppService) Providers(ctx context.Context, opts ...option.RequestOption) (res *AppProvidersResponse, err error) {
opts = append(r.Options[:], opts...)
path := "config/providers"
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
return
}
type App struct { type App struct {
Git bool `json:"git,required"` Git bool `json:"git,required"`
Hostname string `json:"hostname,required"` Hostname string `json:"hostname,required"`
@@ -203,6 +211,145 @@ func (r modeModelJSON) RawJSON() string {
return r.raw return r.raw
} }
type Model struct {
ID string `json:"id,required"`
Attachment bool `json:"attachment,required"`
Cost ModelCost `json:"cost,required"`
Limit ModelLimit `json:"limit,required"`
Name string `json:"name,required"`
Options map[string]interface{} `json:"options,required"`
Reasoning bool `json:"reasoning,required"`
ReleaseDate string `json:"release_date,required"`
Temperature bool `json:"temperature,required"`
ToolCall bool `json:"tool_call,required"`
JSON modelJSON `json:"-"`
}
// modelJSON contains the JSON metadata for the struct [Model]
type modelJSON struct {
ID apijson.Field
Attachment apijson.Field
Cost apijson.Field
Limit apijson.Field
Name apijson.Field
Options apijson.Field
Reasoning apijson.Field
ReleaseDate apijson.Field
Temperature apijson.Field
ToolCall apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *Model) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r modelJSON) RawJSON() string {
return r.raw
}
type ModelCost struct {
Input float64 `json:"input,required"`
Output float64 `json:"output,required"`
CacheRead float64 `json:"cache_read"`
CacheWrite float64 `json:"cache_write"`
JSON modelCostJSON `json:"-"`
}
// modelCostJSON contains the JSON metadata for the struct [ModelCost]
type modelCostJSON struct {
Input apijson.Field
Output apijson.Field
CacheRead apijson.Field
CacheWrite apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *ModelCost) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r modelCostJSON) RawJSON() string {
return r.raw
}
type ModelLimit struct {
Context float64 `json:"context,required"`
Output float64 `json:"output,required"`
JSON modelLimitJSON `json:"-"`
}
// modelLimitJSON contains the JSON metadata for the struct [ModelLimit]
type modelLimitJSON struct {
Context apijson.Field
Output apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *ModelLimit) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r modelLimitJSON) RawJSON() string {
return r.raw
}
type Provider struct {
ID string `json:"id,required"`
Env []string `json:"env,required"`
Models map[string]Model `json:"models,required"`
Name string `json:"name,required"`
API string `json:"api"`
Npm string `json:"npm"`
JSON providerJSON `json:"-"`
}
// providerJSON contains the JSON metadata for the struct [Provider]
type providerJSON struct {
ID apijson.Field
Env apijson.Field
Models apijson.Field
Name apijson.Field
API apijson.Field
Npm apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *Provider) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r providerJSON) RawJSON() string {
return r.raw
}
type AppProvidersResponse struct {
Default map[string]string `json:"default,required"`
Providers []Provider `json:"providers,required"`
JSON appProvidersResponseJSON `json:"-"`
}
// appProvidersResponseJSON contains the JSON metadata for the struct
// [AppProvidersResponse]
type appProvidersResponseJSON struct {
Default apijson.Field
Providers apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *AppProvidersResponse) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r appProvidersResponseJSON) RawJSON() string {
return r.raw
}
type AppLogParams struct { type AppLogParams struct {
// Log level // Log level
Level param.Field[AppLogParamsLevel] `json:"level,required"` Level param.Field[AppLogParamsLevel] `json:"level,required"`
+22
View File
@@ -107,3 +107,25 @@ func TestAppModes(t *testing.T) {
t.Fatalf("err should be nil: %s", err.Error()) t.Fatalf("err should be nil: %s", err.Error())
} }
} }
func TestAppProviders(t *testing.T) {
t.Skip("skipped: tests are disabled for the time being")
baseURL := "http://localhost:4010"
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
baseURL = envURL
}
if !testutil.CheckTestServer(t, baseURL) {
return
}
client := opencode.NewClient(
option.WithBaseURL(baseURL),
)
_, err := client.App.Providers(context.TODO())
if err != nil {
var apierr *opencode.Error
if errors.As(err, &apierr) {
t.Log(string(apierr.DumpRequest(true)))
}
t.Fatalf("err should be nil: %s", err.Error())
}
}
+76 -221
View File
@@ -40,14 +40,6 @@ func (r *ConfigService) Get(ctx context.Context, opts ...option.RequestOption) (
return return
} }
// List all providers
func (r *ConfigService) Providers(ctx context.Context, opts ...option.RequestOption) (res *ConfigProvidersResponse, err error) {
opts = append(r.Options[:], opts...)
path := "config/providers"
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
return
}
type Config struct { type Config struct {
// JSON schema reference for configuration validation // JSON schema reference for configuration validation
Schema string `json:"$schema"` Schema string `json:"$schema"`
@@ -62,11 +54,14 @@ type Config struct {
// Additional instruction files or patterns to include // Additional instruction files or patterns to include
Instructions []string `json:"instructions"` Instructions []string `json:"instructions"`
// Custom keybind configurations // Custom keybind configurations
Keybinds Keybinds `json:"keybinds"` Keybinds KeybindsConfig `json:"keybinds"`
// Layout to use for the TUI
Layout LayoutConfig `json:"layout"`
// Minimum log level to write to log files // Minimum log level to write to log files
LogLevel LogLevel `json:"log_level"` LogLevel LogLevel `json:"log_level"`
// MCP (Model Context Protocol) server configurations // MCP (Model Context Protocol) server configurations
Mcp map[string]ConfigMcp `json:"mcp"` Mcp map[string]ConfigMcp `json:"mcp"`
// Modes configuration, see https://opencode.ai/docs/modes
Mode ConfigMode `json:"mode"` Mode ConfigMode `json:"mode"`
// Model to use in the format of provider/model, eg anthropic/claude-2 // Model to use in the format of provider/model, eg anthropic/claude-2
Model string `json:"model"` Model string `json:"model"`
@@ -91,6 +86,7 @@ type configJSON struct {
Experimental apijson.Field Experimental apijson.Field
Instructions apijson.Field Instructions apijson.Field
Keybinds apijson.Field Keybinds apijson.Field
Layout apijson.Field
LogLevel apijson.Field LogLevel apijson.Field
Mcp apijson.Field Mcp apijson.Field
Mode apijson.Field Mode apijson.Field
@@ -243,12 +239,12 @@ func (r *ConfigMcp) UnmarshalJSON(data []byte) (err error) {
// AsUnion returns a [ConfigMcpUnion] interface which you can cast to the specific // AsUnion returns a [ConfigMcpUnion] interface which you can cast to the specific
// types for more type safety. // types for more type safety.
// //
// Possible runtime types of the union are [McpLocal], [McpRemote]. // Possible runtime types of the union are [McpLocalConfig], [McpRemoteConfig].
func (r ConfigMcp) AsUnion() ConfigMcpUnion { func (r ConfigMcp) AsUnion() ConfigMcpUnion {
return r.union return r.union
} }
// Union satisfied by [McpLocal] or [McpRemote]. // Union satisfied by [McpLocalConfig] or [McpRemoteConfig].
type ConfigMcpUnion interface { type ConfigMcpUnion interface {
implementsConfigMcp() implementsConfigMcp()
} }
@@ -259,12 +255,12 @@ func init() {
"type", "type",
apijson.UnionVariant{ apijson.UnionVariant{
TypeFilter: gjson.JSON, TypeFilter: gjson.JSON,
Type: reflect.TypeOf(McpLocal{}), Type: reflect.TypeOf(McpLocalConfig{}),
DiscriminatorValue: "local", DiscriminatorValue: "local",
}, },
apijson.UnionVariant{ apijson.UnionVariant{
TypeFilter: gjson.JSON, TypeFilter: gjson.JSON,
Type: reflect.TypeOf(McpRemote{}), Type: reflect.TypeOf(McpRemoteConfig{}),
DiscriminatorValue: "remote", DiscriminatorValue: "remote",
}, },
) )
@@ -286,10 +282,11 @@ func (r ConfigMcpType) IsKnown() bool {
return false return false
} }
// Modes configuration, see https://opencode.ai/docs/modes
type ConfigMode struct { type ConfigMode struct {
Build ConfigModeBuild `json:"build"` Build ModeConfig `json:"build"`
Plan ConfigModePlan `json:"plan"` Plan ModeConfig `json:"plan"`
ExtraFields map[string]ConfigMode `json:"-,extras"` ExtraFields map[string]ModeConfig `json:"-,extras"`
JSON configModeJSON `json:"-"` JSON configModeJSON `json:"-"`
} }
@@ -309,54 +306,6 @@ func (r configModeJSON) RawJSON() string {
return r.raw return r.raw
} }
type ConfigModeBuild struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
Tools map[string]bool `json:"tools"`
JSON configModeBuildJSON `json:"-"`
}
// configModeBuildJSON contains the JSON metadata for the struct [ConfigModeBuild]
type configModeBuildJSON struct {
Model apijson.Field
Prompt apijson.Field
Tools apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *ConfigModeBuild) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r configModeBuildJSON) RawJSON() string {
return r.raw
}
type ConfigModePlan struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
Tools map[string]bool `json:"tools"`
JSON configModePlanJSON `json:"-"`
}
// configModePlanJSON contains the JSON metadata for the struct [ConfigModePlan]
type configModePlanJSON struct {
Model apijson.Field
Prompt apijson.Field
Tools apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *ConfigModePlan) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r configModePlanJSON) RawJSON() string {
return r.raw
}
type ConfigProvider struct { type ConfigProvider struct {
Models map[string]ConfigProviderModel `json:"models,required"` Models map[string]ConfigProviderModel `json:"models,required"`
ID string `json:"id"` ID string `json:"id"`
@@ -495,7 +444,7 @@ func (r ConfigShare) IsKnown() bool {
return false return false
} }
type Keybinds struct { type KeybindsConfig struct {
// Exit the application // Exit the application
AppExit string `json:"app_exit,required"` AppExit string `json:"app_exit,required"`
// Show help dialog // Show help dialog
@@ -548,6 +497,8 @@ type Keybinds struct {
ProjectInit string `json:"project_init,required"` ProjectInit string `json:"project_init,required"`
// Compact the session // Compact the session
SessionCompact string `json:"session_compact,required"` SessionCompact string `json:"session_compact,required"`
// Export session to editor
SessionExport string `json:"session_export,required"`
// Interrupt current session // Interrupt current session
SessionInterrupt string `json:"session_interrupt,required"` SessionInterrupt string `json:"session_interrupt,required"`
// List all sessions // List all sessions
@@ -560,15 +511,17 @@ type Keybinds struct {
SessionUnshare string `json:"session_unshare,required"` SessionUnshare string `json:"session_unshare,required"`
// Switch mode // Switch mode
SwitchMode string `json:"switch_mode,required"` SwitchMode string `json:"switch_mode,required"`
// Switch mode reverse
SwitchModeReverse string `json:"switch_mode_reverse,required"`
// List available themes // List available themes
ThemeList string `json:"theme_list,required"` ThemeList string `json:"theme_list,required"`
// Toggle tool details // Toggle tool details
ToolDetails string `json:"tool_details,required"` ToolDetails string `json:"tool_details,required"`
JSON keybindsJSON `json:"-"` JSON keybindsConfigJSON `json:"-"`
} }
// keybindsJSON contains the JSON metadata for the struct [Keybinds] // keybindsConfigJSON contains the JSON metadata for the struct [KeybindsConfig]
type keybindsJSON struct { type keybindsConfigJSON struct {
AppExit apijson.Field AppExit apijson.Field
AppHelp apijson.Field AppHelp apijson.Field
EditorOpen apijson.Field EditorOpen apijson.Field
@@ -595,40 +548,57 @@ type keybindsJSON struct {
ModelList apijson.Field ModelList apijson.Field
ProjectInit apijson.Field ProjectInit apijson.Field
SessionCompact apijson.Field SessionCompact apijson.Field
SessionExport apijson.Field
SessionInterrupt apijson.Field SessionInterrupt apijson.Field
SessionList apijson.Field SessionList apijson.Field
SessionNew apijson.Field SessionNew apijson.Field
SessionShare apijson.Field SessionShare apijson.Field
SessionUnshare apijson.Field SessionUnshare apijson.Field
SwitchMode apijson.Field SwitchMode apijson.Field
SwitchModeReverse apijson.Field
ThemeList apijson.Field ThemeList apijson.Field
ToolDetails apijson.Field ToolDetails apijson.Field
raw string raw string
ExtraFields map[string]apijson.Field ExtraFields map[string]apijson.Field
} }
func (r *Keybinds) UnmarshalJSON(data []byte) (err error) { func (r *KeybindsConfig) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r) return apijson.UnmarshalRoot(data, r)
} }
func (r keybindsJSON) RawJSON() string { func (r keybindsConfigJSON) RawJSON() string {
return r.raw return r.raw
} }
type McpLocal struct { type LayoutConfig string
const (
LayoutConfigAuto LayoutConfig = "auto"
LayoutConfigStretch LayoutConfig = "stretch"
)
func (r LayoutConfig) IsKnown() bool {
switch r {
case LayoutConfigAuto, LayoutConfigStretch:
return true
}
return false
}
type McpLocalConfig struct {
// Command and arguments to run the MCP server // Command and arguments to run the MCP server
Command []string `json:"command,required"` Command []string `json:"command,required"`
// Type of MCP server connection // Type of MCP server connection
Type McpLocalType `json:"type,required"` Type McpLocalConfigType `json:"type,required"`
// Enable or disable the MCP server on startup // Enable or disable the MCP server on startup
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
// Environment variables to set when running the MCP server // Environment variables to set when running the MCP server
Environment map[string]string `json:"environment"` Environment map[string]string `json:"environment"`
JSON mcpLocalJSON `json:"-"` JSON mcpLocalConfigJSON `json:"-"`
} }
// mcpLocalJSON contains the JSON metadata for the struct [McpLocal] // mcpLocalConfigJSON contains the JSON metadata for the struct [McpLocalConfig]
type mcpLocalJSON struct { type mcpLocalConfigJSON struct {
Command apijson.Field Command apijson.Field
Type apijson.Field Type apijson.Field
Enabled apijson.Field Enabled apijson.Field
@@ -637,43 +607,43 @@ type mcpLocalJSON struct {
ExtraFields map[string]apijson.Field ExtraFields map[string]apijson.Field
} }
func (r *McpLocal) UnmarshalJSON(data []byte) (err error) { func (r *McpLocalConfig) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r) return apijson.UnmarshalRoot(data, r)
} }
func (r mcpLocalJSON) RawJSON() string { func (r mcpLocalConfigJSON) RawJSON() string {
return r.raw return r.raw
} }
func (r McpLocal) implementsConfigMcp() {} func (r McpLocalConfig) implementsConfigMcp() {}
// Type of MCP server connection // Type of MCP server connection
type McpLocalType string type McpLocalConfigType string
const ( const (
McpLocalTypeLocal McpLocalType = "local" McpLocalConfigTypeLocal McpLocalConfigType = "local"
) )
func (r McpLocalType) IsKnown() bool { func (r McpLocalConfigType) IsKnown() bool {
switch r { switch r {
case McpLocalTypeLocal: case McpLocalConfigTypeLocal:
return true return true
} }
return false return false
} }
type McpRemote struct { type McpRemoteConfig struct {
// Type of MCP server connection // Type of MCP server connection
Type McpRemoteType `json:"type,required"` Type McpRemoteConfigType `json:"type,required"`
// URL of the remote MCP server // URL of the remote MCP server
URL string `json:"url,required"` URL string `json:"url,required"`
// Enable or disable the MCP server on startup // Enable or disable the MCP server on startup
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
JSON mcpRemoteJSON `json:"-"` JSON mcpRemoteConfigJSON `json:"-"`
} }
// mcpRemoteJSON contains the JSON metadata for the struct [McpRemote] // mcpRemoteConfigJSON contains the JSON metadata for the struct [McpRemoteConfig]
type mcpRemoteJSON struct { type mcpRemoteConfigJSON struct {
Type apijson.Field Type apijson.Field
URL apijson.Field URL apijson.Field
Enabled apijson.Field Enabled apijson.Field
@@ -681,166 +651,51 @@ type mcpRemoteJSON struct {
ExtraFields map[string]apijson.Field ExtraFields map[string]apijson.Field
} }
func (r *McpRemote) UnmarshalJSON(data []byte) (err error) { func (r *McpRemoteConfig) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r) return apijson.UnmarshalRoot(data, r)
} }
func (r mcpRemoteJSON) RawJSON() string { func (r mcpRemoteConfigJSON) RawJSON() string {
return r.raw return r.raw
} }
func (r McpRemote) implementsConfigMcp() {} func (r McpRemoteConfig) implementsConfigMcp() {}
// Type of MCP server connection // Type of MCP server connection
type McpRemoteType string type McpRemoteConfigType string
const ( const (
McpRemoteTypeRemote McpRemoteType = "remote" McpRemoteConfigTypeRemote McpRemoteConfigType = "remote"
) )
func (r McpRemoteType) IsKnown() bool { func (r McpRemoteConfigType) IsKnown() bool {
switch r { switch r {
case McpRemoteTypeRemote: case McpRemoteConfigTypeRemote:
return true return true
} }
return false return false
} }
type Model struct { type ModeConfig struct {
ID string `json:"id,required"` Model string `json:"model"`
Attachment bool `json:"attachment,required"` Prompt string `json:"prompt"`
Cost ModelCost `json:"cost,required"` Tools map[string]bool `json:"tools"`
Limit ModelLimit `json:"limit,required"` JSON modeConfigJSON `json:"-"`
Name string `json:"name,required"`
Options map[string]interface{} `json:"options,required"`
Reasoning bool `json:"reasoning,required"`
ReleaseDate string `json:"release_date,required"`
Temperature bool `json:"temperature,required"`
ToolCall bool `json:"tool_call,required"`
JSON modelJSON `json:"-"`
} }
// modelJSON contains the JSON metadata for the struct [Model] // modeConfigJSON contains the JSON metadata for the struct [ModeConfig]
type modelJSON struct { type modeConfigJSON struct {
ID apijson.Field Model apijson.Field
Attachment apijson.Field Prompt apijson.Field
Cost apijson.Field Tools apijson.Field
Limit apijson.Field
Name apijson.Field
Options apijson.Field
Reasoning apijson.Field
ReleaseDate apijson.Field
Temperature apijson.Field
ToolCall apijson.Field
raw string raw string
ExtraFields map[string]apijson.Field ExtraFields map[string]apijson.Field
} }
func (r *Model) UnmarshalJSON(data []byte) (err error) { func (r *ModeConfig) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r) return apijson.UnmarshalRoot(data, r)
} }
func (r modelJSON) RawJSON() string { func (r modeConfigJSON) RawJSON() string {
return r.raw
}
type ModelCost struct {
Input float64 `json:"input,required"`
Output float64 `json:"output,required"`
CacheRead float64 `json:"cache_read"`
CacheWrite float64 `json:"cache_write"`
JSON modelCostJSON `json:"-"`
}
// modelCostJSON contains the JSON metadata for the struct [ModelCost]
type modelCostJSON struct {
Input apijson.Field
Output apijson.Field
CacheRead apijson.Field
CacheWrite apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *ModelCost) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r modelCostJSON) RawJSON() string {
return r.raw
}
type ModelLimit struct {
Context float64 `json:"context,required"`
Output float64 `json:"output,required"`
JSON modelLimitJSON `json:"-"`
}
// modelLimitJSON contains the JSON metadata for the struct [ModelLimit]
type modelLimitJSON struct {
Context apijson.Field
Output apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *ModelLimit) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r modelLimitJSON) RawJSON() string {
return r.raw
}
type Provider struct {
ID string `json:"id,required"`
Env []string `json:"env,required"`
Models map[string]Model `json:"models,required"`
Name string `json:"name,required"`
API string `json:"api"`
Npm string `json:"npm"`
JSON providerJSON `json:"-"`
}
// providerJSON contains the JSON metadata for the struct [Provider]
type providerJSON struct {
ID apijson.Field
Env apijson.Field
Models apijson.Field
Name apijson.Field
API apijson.Field
Npm apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *Provider) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r providerJSON) RawJSON() string {
return r.raw
}
type ConfigProvidersResponse struct {
Default map[string]string `json:"default,required"`
Providers []Provider `json:"providers,required"`
JSON configProvidersResponseJSON `json:"-"`
}
// configProvidersResponseJSON contains the JSON metadata for the struct
// [ConfigProvidersResponse]
type configProvidersResponseJSON struct {
Default apijson.Field
Providers apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *ConfigProvidersResponse) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r configProvidersResponseJSON) RawJSON() string {
return r.raw return r.raw
} }
-22
View File
@@ -34,25 +34,3 @@ func TestConfigGet(t *testing.T) {
t.Fatalf("err should be nil: %s", err.Error()) t.Fatalf("err should be nil: %s", err.Error())
} }
} }
func TestConfigProviders(t *testing.T) {
t.Skip("skipped: tests are disabled for the time being")
baseURL := "http://localhost:4010"
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
baseURL = envURL
}
if !testutil.CheckTestServer(t, baseURL) {
return
}
client := opencode.NewClient(
option.WithBaseURL(baseURL),
)
_, err := client.Config.Providers(context.TODO())
if err != nil {
var apierr *opencode.Error
if errors.As(err, &apierr) {
t.Log(string(apierr.DumpRequest(true)))
}
t.Fatalf("err should be nil: %s", err.Error())
}
}
+1
View File
@@ -33,6 +33,7 @@ export default defineConfig({
solidJs(), solidJs(),
starlight({ starlight({
title: "opencode", title: "opencode",
lastUpdated: true,
expressiveCode: { themes: ["github-light", "github-dark"] }, expressiveCode: { themes: ["github-light", "github-dark"] },
social: [ social: [
{ icon: "github", label: "GitHub", href: config.github }, { icon: "github", label: "GitHub", href: config.github },
+1
View File
@@ -27,6 +27,7 @@
"marked": "15.0.12", "marked": "15.0.12",
"marked-shiki": "1.2.0", "marked-shiki": "1.2.0",
"rehype-autolink-headings": "7.1.0", "rehype-autolink-headings": "7.1.0",
"remeda": "2.26.0",
"sharp": "0.32.5", "sharp": "0.32.5",
"shiki": "3.4.2", "shiki": "3.4.2",
"solid-js": "1.9.7", "solid-js": "1.9.7",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 540 KiB

After

Width:  |  Height:  |  Size: 592 KiB

+3 -1
View File
@@ -1,6 +1,7 @@
import { For, Show, onMount, Suspense, onCleanup, createMemo, createSignal, SuspenseList, createEffect } from "solid-js" import { For, Show, onMount, Suspense, onCleanup, createMemo, createSignal, SuspenseList, createEffect } from "solid-js"
import { DateTime } from "luxon" import { DateTime } from "luxon"
import { createStore, reconcile, unwrap } from "solid-js/store" import { createStore, reconcile, unwrap } from "solid-js/store"
import { mapValues } from "remeda"
import { IconArrowDown } from "./icons" import { IconArrowDown } from "./icons"
import { IconOpencode } from "./icons/custom" import { IconOpencode } from "./icons/custom"
import styles from "./share.module.css" import styles from "./share.module.css"
@@ -60,7 +61,7 @@ export default function Share(props: {
const [store, setStore] = createStore<{ const [store, setStore] = createStore<{
info?: Session.Info info?: Session.Info
messages: Record<string, MessageWithParts> messages: Record<string, MessageWithParts>
}>({ info: props.info, messages: props.messages }) }>({ info: props.info, messages: mapValues(props.messages, (x: any) => "metadata" in x ? fromV1(x) : x) })
const messages = createMemo(() => Object.values(store.messages).toSorted((a, b) => a.id?.localeCompare(b.id))) const messages = createMemo(() => Object.values(store.messages).toSorted((a, b) => a.id?.localeCompare(b.id)))
const [connectionStatus, setConnectionStatus] = createSignal<[Status, string?]>(["disconnected", "Disconnected"]) const [connectionStatus, setConnectionStatus] = createSignal<[Status, string?]>(["disconnected", "Disconnected"])
createEffect(() => { createEffect(() => {
@@ -340,6 +341,7 @@ export default function Share(props: {
const filteredParts = createMemo(() => const filteredParts = createMemo(() =>
msg.parts.filter((x, index) => { msg.parts.filter((x, index) => {
if (x.type === "step-start" && index > 0) return false if (x.type === "step-start" && index > 0) return false
if (x.type === "snapshot") return false
if (x.type === "step-finish") return false if (x.type === "step-finish") return false
if (x.type === "text" && x.synthetic === true) return false if (x.type === "text" && x.synthetic === true) return false
if (x.type === "tool" && x.tool === "todoread") return false if (x.type === "tool" && x.tool === "todoread") return false
@@ -58,3 +58,11 @@ export function IconMeta(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
</svg> </svg>
) )
} }
// https://icones.js.org/collection/ri?s=robot&icon=ri:robot-2-line
export function IconRobot(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
return (
<svg {...props} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path fill="currentColor" d="M13.5 2c0 .444-.193.843-.5 1.118V5h5a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V8a3 3 0 0 1 3-3h5V3.118A1.5 1.5 0 1 1 13.5 2M6 7a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1zm-4 3H0v6h2zm20 0h2v6h-2zM9 14.5a1.5 1.5 0 1 0 0-3a1.5 1.5 0 0 0 0 3m6 0a1.5 1.5 0 1 0 0-3a1.5 1.5 0 0 0 0 3" /></svg>
)
}
@@ -1,4 +1,4 @@
import { codeToHtml } from "shiki" import { codeToHtml, bundledLanguages } from "shiki"
import { createResource, Suspense } from "solid-js" import { createResource, Suspense } from "solid-js"
import { transformerNotationDiff } from "@shikijs/transformers" import { transformerNotationDiff } from "@shikijs/transformers"
import style from "./content-code.module.css" import style from "./content-code.module.css"
@@ -15,7 +15,7 @@ export function ContentCode(props: Props) {
// TODO: For testing delays // TODO: For testing delays
// await new Promise((resolve) => setTimeout(resolve, 3000)) // await new Promise((resolve) => setTimeout(resolve, 3000))
return (await codeToHtml(code || "", { return (await codeToHtml(code || "", {
lang: lang || "text", lang: lang && lang in bundledLanguages ? lang : "text",
themes: { themes: {
light: "github-light", light: "github-light",
dark: "github-dark", dark: "github-dark",
@@ -23,6 +23,20 @@
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
align-items: stretch; align-items: stretch;
&:first-child {
[data-slot="before"],
[data-slot="after"] {
padding-top: 0.25rem;
}
}
&:last-child {
[data-slot="before"],
[data-slot="after"] {
padding-bottom: 0.25rem;
}
}
[data-slot="before"], [data-slot="before"],
[data-slot="after"] { [data-slot="after"] {
position: relative; position: relative;
@@ -75,46 +89,16 @@
} }
} }
/* .diff > .row:first-child [data-section="cell"]:first-child { */
/* padding-top: 0.5rem; */
/* } */
/**/
/* .diff > .row:last-child [data-section="cell"]:last-child { */
/* padding-bottom: 0.5rem; */
/* } */
/**/
/* [data-section="cell"] { */
/* position: relative; */
/* flex: 1; */
/* display: flex; */
/* flex-direction: column; */
/**/
/* width: 100%; */
/* padding: 0.1875rem 0.5rem 0.1875rem 2.2ch; */
/* margin: 0; */
/**/
/* &[data-display-mobile="true"] { */
/* display: none; */
/* } */
/**/
/* pre { */
/* --shiki-dark-bg: var(--sl-color-bg-surface) !important; */
/* background-color: var(--sl-color-bg-surface) !important; */
/**/
/* white-space: pre-wrap; */
/* word-break: break-word; */
/**/
/* code > span:empty::before { */
/* content: "\00a0"; */
/* white-space: pre; */
/* display: inline-block; */
/* width: 0; */
/* } */
/* } */
/* } */
[data-component="mobile"] { [data-component="mobile"] {
& > [data-component="diff-block"]:first-child > div {
padding-top: 0.25rem;
}
& > [data-component="diff-block"]:last-child > div {
padding-bottom: 0.25rem;
}
& > [data-component="diff-block"] > div { & > [data-component="diff-block"] > div {
padding: 0 1rem 0 2.2ch; padding: 0 1rem 0 2.2ch;
@@ -1,5 +1,5 @@
import { type Component, createMemo } from "solid-js"
import { parsePatch } from "diff" import { parsePatch } from "diff"
import { createMemo } from "solid-js"
import { ContentCode } from "./content-code" import { ContentCode } from "./content-code"
import styles from "./content-diff.module.css" import styles from "./content-diff.module.css"
@@ -90,8 +90,8 @@ export function ContentDiff(props: Props) {
i++ i++
} else if (prefix === " ") { } else if (prefix === " ") {
diffRows.push({ diffRows.push({
left: content, left: content === "" ? " " : content,
right: content, right: content === "" ? " " : content,
type: "unchanged", type: "unchanged",
}) })
i++ i++
@@ -1,21 +1,13 @@
.root { .root {
border: 1px solid var(--sl-color-blue-high);
padding: 0.5rem calc(0.5rem + 3px);
border-radius: 0.25rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
gap: 1rem; gap: 1rem;
align-self: flex-start;
&[data-highlight="true"] {
background-color: var(--sl-color-blue-low);
}
[data-slot="expand-button"] { [data-slot="expand-button"] {
flex: 0 0 auto; flex: 0 0 auto;
padding: 2px 0; padding: 2px 0;
font-size: 0.75rem; font-size: 0.857em;
} }
[data-slot="markdown"] { [data-slot="markdown"] {
@@ -29,7 +21,7 @@
display: block; display: block;
} }
font-size: 0.875rem; font-size: 1em;
line-height: 1.5; line-height: 1.5;
p, p,
@@ -61,7 +53,7 @@
h4, h4,
h5, h5,
h6 { h6 {
font-size: 0.875rem; font-size: 1em;
font-weight: 600; font-weight: 600;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
@@ -75,7 +67,7 @@
background-color: var(--sl-color-bg-surface) !important; background-color: var(--sl-color-bg-surface) !important;
padding: 0.5rem 0.75rem; padding: 0.5rem 0.75rem;
line-height: 1.6; line-height: 1.6;
font-size: 0.75rem; font-size: 0.857em;
white-space: pre-wrap; white-space: pre-wrap;
word-break: break-word; word-break: break-word;
@@ -1,10 +1,11 @@
import style from "./content-markdown.module.css"
import { createResource, createSignal } from "solid-js"
import { createOverflow } from "./common"
import { transformerNotationDiff } from "@shikijs/transformers"
import { marked } from "marked" import { marked } from "marked"
import markedShiki from "marked-shiki"
import { codeToHtml } from "shiki" import { codeToHtml } from "shiki"
import markedShiki from "marked-shiki"
import { createOverflow } from "./common"
import { CopyButton } from "./copy-button"
import { createResource, createSignal } from "solid-js"
import { transformerNotationDiff } from "@shikijs/transformers"
import style from "./content-markdown.module.css"
const markedWithShiki = marked.use( const markedWithShiki = marked.use(
markedShiki({ markedShiki({
@@ -54,6 +55,7 @@ export function ContentMarkdown(props: Props) {
{expanded() ? "Show less" : "Show more"} {expanded() ? "Show less" : "Show more"}
</button> </button>
)} )}
<CopyButton text={props.text} />
</div> </div>
) )
} }
@@ -2,6 +2,7 @@
color: var(--sl-color-text); color: var(--sl-color-text);
background-color: var(--sl-color-bg-surface); background-color: var(--sl-color-bg-surface);
padding: 0.5rem calc(0.5rem + 3px); padding: 0.5rem calc(0.5rem + 3px);
padding-right: calc(1rem + 18px);
border-radius: 0.25rem; border-radius: 0.25rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -0,0 +1,31 @@
.root {
position: absolute;
opacity: 0;
visibility: hidden;
transition: opacity 0.15s ease;
button {
cursor: pointer;
background: none;
border: none;
padding: 0.125rem;
background-color: var(--sl-color-bg);
color: var(--sl-color-text-secondary);
svg {
display: block;
width: 1rem;
height: 1rem;
}
&[data-copied="true"] {
color: var(--sl-color-green-high);
}
}
}
/* Show copy button when parent is hovered */
*:hover > .root {
opacity: 1;
visibility: visible;
}
@@ -0,0 +1,36 @@
import { createSignal } from "solid-js"
import { IconClipboard, IconCheckCircle } from "../icons"
import styles from "./copy-button.module.css"
interface CopyButtonProps {
text: string
}
export function CopyButton(props: CopyButtonProps) {
const [copied, setCopied] = createSignal(false)
function handleCopyClick() {
if (props.text) {
navigator.clipboard.writeText(props.text)
.catch((err) => console.error("Copy failed", err))
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
}
return (
<div data-component="copy-button" class={styles.root}>
<button
type="button"
onClick={handleCopyClick}
data-copied={copied() ? true : undefined}
>
{copied()
? <IconCheckCircle width={16} height={16} />
: <IconClipboard width={16} height={16} />
}
</button>
</div>
)
}
@@ -103,7 +103,7 @@
[data-component="content"] { [data-component="content"] {
flex: 1 1 auto; flex: 1 1 auto;
min-width: 0; min-width: 0;
padding: 0 0 0.375rem; padding: 0 0 1rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1rem; gap: 1rem;
@@ -135,6 +135,20 @@
gap: 1rem; gap: 1rem;
flex-grow: 1; flex-grow: 1;
max-width: var(--md-tool-width); max-width: var(--md-tool-width);
& > [data-component="assistant-text-markdown"] {
align-self: flex-start;
font-size: 0.875rem;
border: 1px solid var(--sl-color-blue-high);
padding: 0.5rem calc(0.5rem + 3px);
border-radius: 0.25rem;
position: relative;
[data-component="copy-button"] {
top: 0.5rem;
right: calc(0.5rem - 1px);
}
}
} }
[data-component="step-start"] { [data-component="step-start"] {
@@ -142,7 +156,6 @@
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
gap: 0.375rem; gap: 0.375rem;
padding-bottom: 1rem;
[data-slot="provider"] { [data-slot="provider"] {
line-height: 18px; line-height: 18px;
@@ -237,6 +250,32 @@
&[data-tool="edit"] { &[data-tool="edit"] {
[data-component="tool-result"] { [data-component="tool-result"] {
max-width: var(--lg-tool-width); max-width: var(--lg-tool-width);
align-items: stretch;
width: 100%;
}
}
&[data-tool="task"] {
[data-component="tool-input"] {
font-size: 0.75rem;
line-height: 1.5;
max-width: var(--md-tool-width);
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
[data-component="tool-output"] {
max-width: var(--sm-tool-width);
font-size: 0.75rem;
border: 1px solid var(--sl-color-divider);
padding: 0.5rem calc(0.5rem + 3px);
border-radius: 0.25rem;
position: relative;
[data-component="copy-button"] {
top: 0.5rem;
right: calc(0.5rem - 1px);
}
} }
} }
} }
+40 -20
View File
@@ -19,25 +19,25 @@ import {
IconMagnifyingGlass, IconMagnifyingGlass,
IconDocumentMagnifyingGlass, IconDocumentMagnifyingGlass,
} from "../icons" } from "../icons"
import { IconMeta, IconOpenAI, IconGemini, IconAnthropic } from "../icons/custom" import { IconMeta, IconRobot, IconOpenAI, IconGemini, IconAnthropic } from "../icons/custom"
import { formatDuration } from "../share/common"
import { ContentCode } from "./content-code" import { ContentCode } from "./content-code"
import { ContentDiff } from "./content-diff" import { ContentDiff } from "./content-diff"
import { ContentText } from "./content-text" import { ContentText } from "./content-text"
import { ContentError } from "./content-error"
import { ContentMarkdown } from "./content-markdown"
import { ContentBash } from "./content-bash" import { ContentBash } from "./content-bash"
import { ContentError } from "./content-error"
import { formatDuration } from "../share/common"
import { ContentMarkdown } from "./content-markdown"
import type { MessageV2 } from "opencode/session/message-v2" import type { MessageV2 } from "opencode/session/message-v2"
import type { Diagnostic } from "vscode-languageserver-types" import type { Diagnostic } from "vscode-languageserver-types"
import styles from "./part.module.css" import styles from "./part.module.css"
const MIN_DURATION = 2 const MIN_DURATION = 2000
export interface PartProps { export interface PartProps {
index: number index: number
message: MessageV2.Info message: MessageV2.Info
part: MessageV2.AssistantPart | MessageV2.UserPart part: MessageV2.Part
last: boolean last: boolean
} }
@@ -114,7 +114,7 @@ export function Part(props: PartProps) {
<IconGlobeAlt width={18} height={18} /> <IconGlobeAlt width={18} height={18} />
</Match> </Match>
<Match when={props.part.type === "tool" && props.part.tool === "task"}> <Match when={props.part.type === "tool" && props.part.tool === "task"}>
<IconRectangleStack width={18} height={18} /> <IconRobot width={18} height={18} />
</Match> </Match>
<Match when={true}> <Match when={true}>
<IconSparkles width={18} height={18} /> <IconSparkles width={18} height={18} />
@@ -131,12 +131,13 @@ export function Part(props: PartProps) {
{props.message.role === "user" && props.part.type === "text" && ( {props.message.role === "user" && props.part.type === "text" && (
<div data-component="user-text"> <div data-component="user-text">
<ContentText text={props.part.text} expand={props.last} /> <ContentText text={props.part.text} expand={props.last} />
<Spacer />
</div> </div>
)} )}
{props.message.role === "assistant" && props.part.type === "text" && ( {props.message.role === "assistant" && props.part.type === "text" && (
<div data-component="assistant-text"> <div data-component="assistant-text">
<div data-component="assistant-text-markdown">
<ContentMarkdown expand={props.last} text={props.part.text} /> <ContentMarkdown expand={props.last} text={props.part.text} />
</div>
{props.last && props.message.role === "assistant" && props.message.time.completed && ( {props.last && props.message.role === "assistant" && props.message.time.completed && (
<Footer <Footer
title={DateTime.fromMillis(props.message.time.completed).toLocaleString( title={DateTime.fromMillis(props.message.time.completed).toLocaleString(
@@ -146,7 +147,6 @@ export function Part(props: PartProps) {
{DateTime.fromMillis(props.message.time.completed).toLocaleString(DateTime.DATETIME_MED)} {DateTime.fromMillis(props.message.time.completed).toLocaleString(DateTime.DATETIME_MED)}
</Footer> </Footer>
)} )}
<Spacer />
</div> </div>
)} )}
{props.message.role === "user" && props.part.type === "file" && ( {props.message.role === "user" && props.part.type === "file" && (
@@ -245,6 +245,14 @@ export function Part(props: PartProps) {
state={props.part.state} state={props.part.state}
/> />
</Match> </Match>
<Match when={props.part.tool === "task"}>
<TaskTool
id={props.part.id}
tool={props.part.tool}
message={props.message}
state={props.part.state}
/>
</Match>
<Match when={true}> <Match when={true}>
<FallbackTool <FallbackTool
message={props.message} message={props.message}
@@ -256,11 +264,10 @@ export function Part(props: PartProps) {
</Switch> </Switch>
</div> </div>
<ToolFooter <ToolFooter
time={ time={DateTime.fromMillis(props.part.state.time.end)
DateTime.fromMillis(props.part.state.time.start) .diff(DateTime.fromMillis(props.part.state.time.start))
.diff(DateTime.fromMillis(props.part.state.time.end)) .toMillis()}
.toMillis() />
} />
</> </>
)} )}
</div> </div>
@@ -636,12 +643,25 @@ function Footer(props: ParentProps<{ title: string }>) {
} }
function ToolFooter(props: { time: number }) { function ToolFooter(props: { time: number }) {
return props.time > MIN_DURATION ? ( return props.time > MIN_DURATION && <Footer title={`${props.time}ms`}>{formatDuration(props.time)}</Footer>
<Footer title={`${props.time}ms`}> }
{formatDuration(props.time)}
</Footer> function TaskTool(props: ToolProps) {
) : ( return (
<Spacer /> <>
<div data-component="tool-title">
<span data-slot="name">Task</span>
<span data-slot="target">{props.state.input.description}</span>
</div>
<div data-component="tool-input">
&ldquo;{props.state.input.prompt}&rdquo;
</div>
<ResultsButton showCopy="Show output" hideCopy="Hide output">
<div data-component="tool-output">
<ContentMarkdown expand text={props.state.output} />
</div>
</ResultsButton>
</>
) )
} }
@@ -5,7 +5,7 @@ description: Using the opencode JSON config.
You can configure opencode using a JSON config file. You can configure opencode using a JSON config file.
```json title="opencode config" ```json title="opencode.json"
{ {
"$schema": "https://opencode.ai/config.json", "$schema": "https://opencode.ai/config.json",
"theme": "opencode", "theme": "opencode",
@@ -188,7 +188,9 @@ Use `{env:VARIABLE_NAME}` to substitute environment variables:
"model": "{env:OPENCODE_MODEL}", "model": "{env:OPENCODE_MODEL}",
"provider": { "provider": {
"anthropic": { "anthropic": {
"api_key": "{env:ANTHROPIC_API_KEY}" "options": {
"apiKey": "{env:ANTHROPIC_API_KEY}"
}
} }
} }
} }
@@ -208,7 +210,9 @@ Use `{file:path/to/file}` to substitute the contents of a file:
"instructions": ["{file:./custom-instructions.md}"], "instructions": ["{file:./custom-instructions.md}"],
"provider": { "provider": {
"openai": { "openai": {
"api_key": "{file:~/.secrets/openai-key}" "options": {
"apiKey": "{file:~/.secrets/openai-key}"
}
} }
} }
} }
@@ -61,3 +61,30 @@ This can be switched to a centralized authentication system that your organizati
The share feature can be self-hosted and the share pages can be made accessible The share feature can be self-hosted and the share pages can be made accessible
only after the user has been authenticated. only after the user has been authenticated.
---
### Private NPM registries
opencode supports private npm registries through Bun's native `.npmrc` file support. If your organization uses a private registry (such as JFrog Artifactory, Nexus, or similar), ensure developers are authenticated before running opencode.
To set up authentication with your private registry:
```bash
# Authenticate with your enterprise registry
npm login --registry=https://your-company.jfrog.io/api/npm/npm-virtual/
# This creates ~/.npmrc with authentication
# opencode will automatically use it through Bun's native support
```
Alternatively, you can manually configure a `.npmrc` file:
```bash
# ~/.npmrc
registry=https://your-company.jfrog.io/api/npm/npm-virtual/
//your-company.jfrog.io/api/npm/npm-virtual/:_authToken=${NPM_AUTH_TOKEN}
```
**Important**: Developers must be logged into the private registry before running opencode
to ensure packages can be installed from your enterprise registry.
+24 -4
View File
@@ -27,14 +27,34 @@ You can add custom providers by specifying the npm package for the provider and
{ {
"$schema": "https://opencode.ai/config.json", "$schema": "https://opencode.ai/config.json",
"provider": { "provider": {
"openrouter": { "moonshot": {
"name": "OpenRouter", "npm": "@ai-sdk/openai-compatible",
"options": {
"baseURL": "https://api.moonshot.ai/v1"
},
"models": { "models": {
"weirdo/some-weird-model": { "kimi-k2-0711-preview": {}
"name": "Claude 3.5 Sonnet"
} }
} }
} }
}
```
---
### Base URL
You can customize the base URL for any provider by setting the `baseURL` option. This is useful when using proxy services or custom endpoints.
```json title="opencode.json" {6-7}
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"anthropic": {
"options": {
"baseURL": "https://api.anthropic.com/v1"
},
}
} }
} }
``` ```
@@ -116,3 +116,31 @@ export DISPLAY=:99.0
``` ```
opencode will detect if you're using Wayland and prefer `wl-clipboard`, otherwise it will try to find clipboard tools in order of: `xclip` and `xsel`. opencode will detect if you're using Wayland and prefer `wl-clipboard`, otherwise it will try to find clipboard tools in order of: `xclip` and `xsel`.
---
### How to select and copy text in the TUI
There are several ways to copy text from opencode's TUI:
- **Copy latest message**: Use `<leader>y` to copy the most recent message in your current session to the clipboard
- **Export session**: Use `/export` (or `<leader>x`) to open the current session as plain text in your `$EDITOR` (requires the `EDITOR` environment variable to be set)
We're working on adding click & drag text selection in a future update.
---
### TUI not rendering full width
By default, opencode's TUI uses an "auto" layout that centers content with padding. If you want the TUI to use the full width of your terminal, you can configure the layout setting:
```json
{
"layout": "stretch"
}
```
Add this to your `opencode.json` configuration file. The available layout options are:
- `"auto"` (default) - Centers content with padding
- `"stretch"` - Uses full terminal width
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bun
import { $ } from "bun"
try {
await $`git tag -d github-v1`
await $`git push origin :refs/tags/github-v1`
} catch (e: any) {
if (e instanceof $.ShellError && e.stderr.toString().match(/tag \S+ not found/)) {
console.log("tag not found, continuing...")
} else {
throw e
}
}
await $`git tag -a github-v1 -m "Update github-v1 to latest"`
await $`git push origin github-v1`
+182 -230
View File
@@ -1,341 +1,299 @@
#!/usr/bin/env bun #!/usr/bin/env bun
import os from "os"; import os from "os"
import path from "path"; import path from "path"
import { $ } from "bun"; import { $ } from "bun"
import { Octokit } from "@octokit/rest"; import { Octokit } from "@octokit/rest"
import { graphql } from "@octokit/graphql"; import { graphql } from "@octokit/graphql"
import * as core from "@actions/core"; import * as core from "@actions/core"
import * as github from "@actions/github"; import * as github from "@actions/github"
import type { IssueCommentEvent } from "@octokit/webhooks-types"; import type { IssueCommentEvent } from "@octokit/webhooks-types"
import type { import type { GitHubIssue, GitHubPullRequest, IssueQueryResponse, PullRequestQueryResponse } from "./types"
GitHubIssue,
GitHubPullRequest,
IssueQueryResponse,
PullRequestQueryResponse,
} from "./types";
if (github.context.eventName !== "issue_comment") { if (github.context.eventName !== "issue_comment") {
core.setFailed(`Unsupported event type: ${github.context.eventName}`); core.setFailed(`Unsupported event type: ${github.context.eventName}`)
process.exit(1); process.exit(1)
} }
const { owner, repo } = github.context.repo; const { owner, repo } = github.context.repo
const payload = github.context.payload as IssueCommentEvent; const payload = github.context.payload as IssueCommentEvent
const actor = github.context.actor; const actor = github.context.actor
const issueId = payload.issue.number; const issueId = payload.issue.number
const body = payload.comment.body; const body = payload.comment.body
let appToken: string; let appToken: string
let octoRest: Octokit; let octoRest: Octokit
let octoGraph: typeof graphql; let octoGraph: typeof graphql
let commentId: number; let commentId: number
let gitCredentials: string; let gitCredentials: string
let shareUrl: string | undefined; let shareUrl: string | undefined
let state: let state:
| { | {
type: "issue"; type: "issue"
issue: GitHubIssue; issue: GitHubIssue
} }
| { | {
type: "local-pr"; type: "local-pr"
pr: GitHubPullRequest; pr: GitHubPullRequest
} }
| { | {
type: "fork-pr"; type: "fork-pr"
pr: GitHubPullRequest; pr: GitHubPullRequest
}; }
async function run() { async function run() {
try { try {
const match = body.match(/^hey\s*opencode,?\s*(.*)$/); const match = body.match(/^hey\s*opencode,?\s*(.*)$/)
if (!match?.[1]) throw new Error("Command must start with `hey opencode`"); if (!match?.[1]) throw new Error("Command must start with `hey opencode`")
const userPrompt = match[1]; const userPrompt = match[1]
const oidcToken = await generateGitHubToken(); const oidcToken = await generateGitHubToken()
appToken = await exchangeForAppToken(oidcToken); appToken = await exchangeForAppToken(oidcToken)
octoRest = new Octokit({ auth: appToken }); octoRest = new Octokit({ auth: appToken })
octoGraph = graphql.defaults({ octoGraph = graphql.defaults({
headers: { authorization: `token ${appToken}` }, headers: { authorization: `token ${appToken}` },
}); })
await configureGit(appToken); await configureGit(appToken)
await assertPermissions(); await assertPermissions()
const comment = await createComment("opencode started..."); const comment = await createComment("opencode started...")
commentId = comment.data.id; commentId = comment.data.id
// Set state // Set state
const repoData = await fetchRepo(); const repoData = await fetchRepo()
if (payload.issue.pull_request) { if (payload.issue.pull_request) {
const prData = await fetchPR(); const prData = await fetchPR()
state = { state = {
type: type: prData.headRepository.nameWithOwner === prData.baseRepository.nameWithOwner ? "local-pr" : "fork-pr",
prData.headRepository.nameWithOwner ===
prData.baseRepository.nameWithOwner
? "local-pr"
: "fork-pr",
pr: prData, pr: prData,
}; }
} else { } else {
state = { state = {
type: "issue", type: "issue",
issue: await fetchIssue(), issue: await fetchIssue(),
}; }
} }
// Setup git branch // Setup git branch
if (state.type === "local-pr") await checkoutLocalBranch(state.pr); if (state.type === "local-pr") await checkoutLocalBranch(state.pr)
else if (state.type === "fork-pr") await checkoutForkBranch(state.pr); else if (state.type === "fork-pr") await checkoutForkBranch(state.pr)
// Prompt // Prompt
const share = process.env.INPUT_SHARE === "true" || !repoData.data.private; const share = process.env.INPUT_SHARE === "true" || !repoData.data.private
const promptData = const promptData = state.type === "issue" ? buildPromptDataForIssue(state.issue) : buildPromptDataForPR(state.pr)
state.type === "issue"
? buildPromptDataForIssue(state.issue)
: buildPromptDataForPR(state.pr);
const responseRet = await runOpencode(`${userPrompt}\n\n${promptData}`, { const responseRet = await runOpencode(`${userPrompt}\n\n${promptData}`, {
share, share,
}); })
const response = responseRet.stdout; const response = responseRet.stdout
shareUrl = responseRet.stderr.match(/https:\/\/opencode\.ai\/s\/\w+/)?.[0]; shareUrl = responseRet.stderr.match(/https:\/\/opencode\.ai\/s\/\w+/)?.[0]
// Comment and push changes // Comment and push changes
if (await branchIsDirty()) { if (await branchIsDirty()) {
const summary = const summary =
( (await runOpencode(`Summarize the following in less than 40 characters:\n\n${response}`, { share: false }))
await runOpencode( ?.stdout || `Fix issue: ${payload.issue.title}`
`Summarize the following in less than 40 characters:\n\n${response}`,
{ share: false }
)
)?.stdout || `Fix issue: ${payload.issue.title}`;
if (state.type === "issue") { if (state.type === "issue") {
const branch = await pushToNewBranch(summary); const branch = await pushToNewBranch(summary)
const pr = await createPR( const pr = await createPR(repoData.data.default_branch, branch, summary, `${response}\n\nCloses #${issueId}`)
repoData.data.default_branch, await updateComment(`opencode created pull request #${pr}`)
branch,
summary,
`${response}\n\nCloses #${issueId}`
);
await updateComment(`opencode created pull request #${pr}`);
} else if (state.type === "local-pr") { } else if (state.type === "local-pr") {
await pushToCurrentBranch(summary); await pushToCurrentBranch(summary)
await updateComment(response); await updateComment(response)
} else if (state.type === "fork-pr") { } else if (state.type === "fork-pr") {
await pushToForkBranch(summary, state.pr); await pushToForkBranch(summary, state.pr)
await updateComment(response); await updateComment(response)
} }
} else { } else {
await updateComment(response); await updateComment(response)
} }
await restoreGitConfig(); await restoreGitConfig()
await revokeAppToken(); await revokeAppToken()
} catch (e: any) { } catch (e: any) {
await restoreGitConfig(); await restoreGitConfig()
await revokeAppToken(); await revokeAppToken()
console.error(e); console.error(e)
let msg = e; let msg = e
if (e instanceof $.ShellError) { if (e instanceof $.ShellError) {
msg = e.stderr.toString(); msg = e.stderr.toString()
} else if (e instanceof Error) { } else if (e instanceof Error) {
msg = e.message; msg = e.message
} }
if (commentId) await updateComment(msg); if (commentId) await updateComment(msg)
core.setFailed(`opencode failed with error: ${msg}`); core.setFailed(`opencode failed with error: ${msg}`)
// Also output the clean error message for the action to capture // Also output the clean error message for the action to capture
//core.setOutput("prepare_error", e.message); //core.setOutput("prepare_error", e.message);
process.exit(1); process.exit(1)
} }
} }
if (import.meta.main) { if (import.meta.main) {
run(); run()
} }
async function generateGitHubToken() { async function generateGitHubToken() {
try { try {
return await core.getIDToken("opencode-github-action"); return await core.getIDToken("opencode-github-action")
} catch (error) { } catch (error) {
console.error("Failed to get OIDC token:", error); console.error("Failed to get OIDC token:", error)
throw new Error( throw new Error("Could not fetch an OIDC token. Make sure to add `id-token: write` to your workflow permissions.")
"Could not fetch an OIDC token. Make sure to add `id-token: write` to your workflow permissions."
);
} }
} }
async function exchangeForAppToken(oidcToken: string) { async function exchangeForAppToken(oidcToken: string) {
const response = await fetch( const response = await fetch("https://api.opencode.ai/exchange_github_app_token", {
"https://api.frank.dev.opencode.ai/exchange_github_app_token",
{
method: "POST", method: "POST",
headers: { headers: {
Authorization: `Bearer ${oidcToken}`, Authorization: `Bearer ${oidcToken}`,
}, },
} })
);
if (!response.ok) { if (!response.ok) {
const responseJson = (await response.json()) as { error?: string }; const responseJson = (await response.json()) as { error?: string }
throw new Error( throw new Error(`App token exchange failed: ${response.status} ${response.statusText} - ${responseJson.error}`)
`App token exchange failed: ${response.status} ${response.statusText} - ${responseJson.error}`
);
} }
const responseJson = (await response.json()) as { token: string }; const responseJson = (await response.json()) as { token: string }
return responseJson.token; return responseJson.token
} }
async function configureGit(appToken: string) { async function configureGit(appToken: string) {
console.log("Configuring git..."); console.log("Configuring git...")
const config = "http.https://github.com/.extraheader"; const config = "http.https://github.com/.extraheader"
const ret = await $`git config --local --get ${config}`; const ret = await $`git config --local --get ${config}`
gitCredentials = ret.stdout.toString().trim(); gitCredentials = ret.stdout.toString().trim()
const newCredentials = Buffer.from( const newCredentials = Buffer.from(`x-access-token:${appToken}`, "utf8").toString("base64")
`x-access-token:${appToken}`,
"utf8"
).toString("base64");
await $`git config --local --unset-all ${config}`; await $`git config --local --unset-all ${config}`
await $`git config --local ${config} "AUTHORIZATION: basic ${newCredentials}"`; await $`git config --local ${config} "AUTHORIZATION: basic ${newCredentials}"`
await $`git config --global user.name "opencode-agent[bot]"`; await $`git config --global user.name "opencode-agent[bot]"`
await $`git config --global user.email "opencode-agent[bot]@users.noreply.github.com"`; await $`git config --global user.email "opencode-agent[bot]@users.noreply.github.com"`
} }
async function checkoutLocalBranch(pr: GitHubPullRequest) { async function checkoutLocalBranch(pr: GitHubPullRequest) {
console.log("Checking out local branch..."); console.log("Checking out local branch...")
const branch = pr.headRefName; const branch = pr.headRefName
const depth = Math.max(pr.commits.totalCount, 20); const depth = Math.max(pr.commits.totalCount, 20)
await $`git fetch origin --depth=${depth} ${branch}`; await $`git fetch origin --depth=${depth} ${branch}`
await $`git checkout ${branch}`; await $`git checkout ${branch}`
} }
async function checkoutForkBranch(pr: GitHubPullRequest) { async function checkoutForkBranch(pr: GitHubPullRequest) {
console.log("Checking out fork branch..."); console.log("Checking out fork branch...")
const remoteBranch = pr.headRefName; const remoteBranch = pr.headRefName
const localBranch = generateBranchName(); const localBranch = generateBranchName()
const depth = Math.max(pr.commits.totalCount, 20); const depth = Math.max(pr.commits.totalCount, 20)
await $`git remote add fork https://github.com/${pr.headRepository.nameWithOwner}.git`; await $`git remote add fork https://github.com/${pr.headRepository.nameWithOwner}.git`
await $`git fetch fork --depth=${depth} ${remoteBranch}`; await $`git fetch fork --depth=${depth} ${remoteBranch}`
await $`git checkout -b ${localBranch} fork/${remoteBranch}`; await $`git checkout -b ${localBranch} fork/${remoteBranch}`
} }
async function restoreGitConfig() { async function restoreGitConfig() {
if (!gitCredentials) return; if (!gitCredentials) return
const config = "http.https://github.com/.extraheader"; const config = "http.https://github.com/.extraheader"
await $`git config --local ${config} "${gitCredentials}"`; await $`git config --local ${config} "${gitCredentials}"`
} }
async function assertPermissions() { async function assertPermissions() {
console.log(`Asserting permissions for user ${actor}...`); console.log(`Asserting permissions for user ${actor}...`)
let permission; let permission
try { try {
const response = await octoRest.repos.getCollaboratorPermissionLevel({ const response = await octoRest.repos.getCollaboratorPermissionLevel({
owner, owner,
repo, repo,
username: actor, username: actor,
}); })
permission = response.data.permission; permission = response.data.permission
console.log(` permission: ${permission}`); console.log(` permission: ${permission}`)
} catch (error) { } catch (error) {
console.error(`Failed to check permissions: ${error}`); console.error(`Failed to check permissions: ${error}`)
throw new Error(`Failed to check permissions for user ${actor}: ${error}`); throw new Error(`Failed to check permissions for user ${actor}: ${error}`)
} }
if (!["admin", "write"].includes(permission)) if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`)
throw new Error(`User ${actor} does not have write permissions`);
} }
function buildComment(content: string) { function buildComment(content: string) {
const runId = process.env.GITHUB_RUN_ID!; const runId = process.env.GITHUB_RUN_ID!
const runUrl = `/${owner}/${repo}/actions/runs/${runId}`; const runUrl = `/${owner}/${repo}/actions/runs/${runId}`
return [ return [content, "\n\n", shareUrl ? `[view session](${shareUrl}) | ` : "", `[view log](${runUrl})`].join("")
content,
"\n\n",
shareUrl ? `[view session](${shareUrl}) | ` : "",
`[view log](${runUrl})`,
].join("");
} }
async function createComment(body: string) { async function createComment(body: string) {
console.log("Creating comment..."); console.log("Creating comment...")
return await octoRest.rest.issues.createComment({ return await octoRest.rest.issues.createComment({
owner, owner,
repo, repo,
issue_number: issueId, issue_number: issueId,
body: buildComment(body), body: buildComment(body),
}); })
} }
async function updateComment(body: string) { async function updateComment(body: string) {
console.log("Updating comment..."); console.log("Updating comment...")
return await octoRest.rest.issues.updateComment({ return await octoRest.rest.issues.updateComment({
owner, owner,
repo, repo,
comment_id: commentId, comment_id: commentId,
body: buildComment(body), body: buildComment(body),
}); })
} }
function generateBranchName() { function generateBranchName() {
const type = state.type === "issue" ? "issue" : "pr"; const type = state.type === "issue" ? "issue" : "pr"
const timestamp = new Date() const timestamp = new Date()
.toISOString() .toISOString()
.replace(/[:-]/g, "") .replace(/[:-]/g, "")
.replace(/\.\d{3}Z/, "") .replace(/\.\d{3}Z/, "")
.split("T") .split("T")
.join("_"); .join("_")
return `opencode/${type}${issueId}-${timestamp}`; return `opencode/${type}${issueId}-${timestamp}`
} }
async function pushToCurrentBranch(summary: string) { async function pushToCurrentBranch(summary: string) {
console.log("Pushing to current branch..."); console.log("Pushing to current branch...")
await $`git add .`; await $`git add .`
await $`git commit -m "${summary} await $`git commit -m "${summary}
Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"`; Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"`
await $`git push`; await $`git push`
} }
async function pushToForkBranch(summary: string, pr: GitHubPullRequest) { async function pushToForkBranch(summary: string, pr: GitHubPullRequest) {
console.log("Pushing to fork branch..."); console.log("Pushing to fork branch...")
const remoteBranch = pr.headRefName; const remoteBranch = pr.headRefName
await $`git add .`; await $`git add .`
await $`git commit -m "${summary} await $`git commit -m "${summary}
Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"`; Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"`
await $`git push fork HEAD:${remoteBranch}`; await $`git push fork HEAD:${remoteBranch}`
} }
async function pushToNewBranch(summary: string) { async function pushToNewBranch(summary: string) {
console.log("Pushing to new branch..."); console.log("Pushing to new branch...")
const branch = generateBranchName(); const branch = generateBranchName()
await $`git checkout -b ${branch}`; await $`git checkout -b ${branch}`
await $`git add .`; await $`git add .`
await $`git commit -m "${summary} await $`git commit -m "${summary}
Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"`; Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"`
await $`git push -u origin ${branch}`; await $`git push -u origin ${branch}`
return branch; return branch
} }
async function createPR( async function createPR(base: string, branch: string, title: string, body: string) {
base: string, console.log("Creating pull request...")
branch: string,
title: string,
body: string
) {
console.log("Creating pull request...");
const pr = await octoRest.rest.pulls.create({ const pr = await octoRest.rest.pulls.create({
owner, owner,
repo, repo,
@@ -343,41 +301,39 @@ async function createPR(
base, base,
title, title,
body: buildComment(body), body: buildComment(body),
}); })
return pr.data.number; return pr.data.number
} }
async function runOpencode( async function runOpencode(
prompt: string, prompt: string,
opts?: { opts?: {
share?: boolean; share?: boolean
} },
) { ) {
console.log("Running opencode..."); console.log("Running opencode...")
const promptPath = path.join(os.tmpdir(), "PROMPT"); const promptPath = path.join(os.tmpdir(), "PROMPT")
await Bun.write(promptPath, prompt); await Bun.write(promptPath, prompt)
const ret = await $`cat ${promptPath} | opencode run -m ${ const ret = await $`cat ${promptPath} | opencode run -m ${process.env.INPUT_MODEL} ${opts?.share ? "--share" : ""}`
process.env.INPUT_MODEL
} ${opts?.share ? "--share" : ""}`;
return { return {
stdout: ret.stdout.toString().trim(), stdout: ret.stdout.toString().trim(),
stderr: ret.stderr.toString().trim(), stderr: ret.stderr.toString().trim(),
}; }
} }
async function branchIsDirty() { async function branchIsDirty() {
console.log("Checking if branch is dirty..."); console.log("Checking if branch is dirty...")
const ret = await $`git status --porcelain`; const ret = await $`git status --porcelain`
return ret.stdout.toString().trim().length > 0; return ret.stdout.toString().trim().length > 0
} }
async function fetchRepo() { async function fetchRepo() {
return await octoRest.rest.repos.get({ owner, repo }); return await octoRest.rest.repos.get({ owner, repo })
} }
async function fetchIssue() { async function fetchIssue() {
console.log("Fetching prompt data for issue..."); console.log("Fetching prompt data for issue...")
const issueResult = await octoGraph<IssueQueryResponse>( const issueResult = await octoGraph<IssueQueryResponse>(
` `
query($owner: String!, $repo: String!, $number: Int!) { query($owner: String!, $repo: String!, $number: Int!) {
@@ -408,22 +364,22 @@ query($owner: String!, $repo: String!, $number: Int!) {
owner, owner,
repo, repo,
number: issueId, number: issueId,
} },
); )
const issue = issueResult.repository.issue; const issue = issueResult.repository.issue
if (!issue) throw new Error(`Issue #${issueId} not found`); if (!issue) throw new Error(`Issue #${issueId} not found`)
return issue; return issue
} }
function buildPromptDataForIssue(issue: GitHubIssue) { function buildPromptDataForIssue(issue: GitHubIssue) {
const comments = (issue.comments?.nodes || []) const comments = (issue.comments?.nodes || [])
.filter((c) => { .filter((c) => {
const id = parseInt(c.databaseId); const id = parseInt(c.databaseId)
return id !== commentId && id !== payload.comment.id; return id !== commentId && id !== payload.comment.id
}) })
.map((c) => ` - ${c.author.login} at ${c.createdAt}: ${c.body}`); .map((c) => ` - ${c.author.login} at ${c.createdAt}: ${c.body}`)
return [ return [
"Here is the context for the issue:", "Here is the context for the issue:",
@@ -433,11 +389,11 @@ function buildPromptDataForIssue(issue: GitHubIssue) {
`- Created At: ${issue.createdAt}`, `- Created At: ${issue.createdAt}`,
`- State: ${issue.state}`, `- State: ${issue.state}`,
...(comments.length > 0 ? ["- Comments:", ...comments] : []), ...(comments.length > 0 ? ["- Comments:", ...comments] : []),
].join("\n"); ].join("\n")
} }
async function fetchPR() { async function fetchPR() {
console.log("Fetching prompt data for PR..."); console.log("Fetching prompt data for PR...")
const prResult = await octoGraph<PullRequestQueryResponse>( const prResult = await octoGraph<PullRequestQueryResponse>(
` `
query($owner: String!, $repo: String!, $number: Int!) { query($owner: String!, $repo: String!, $number: Int!) {
@@ -525,36 +481,32 @@ query($owner: String!, $repo: String!, $number: Int!) {
owner, owner,
repo, repo,
number: issueId, number: issueId,
} },
); )
const pr = prResult.repository.pullRequest; const pr = prResult.repository.pullRequest
if (!pr) throw new Error(`PR #${issueId} not found`); if (!pr) throw new Error(`PR #${issueId} not found`)
return pr; return pr
} }
function buildPromptDataForPR(pr: GitHubPullRequest) { function buildPromptDataForPR(pr: GitHubPullRequest) {
const comments = (pr.comments?.nodes || []) const comments = (pr.comments?.nodes || [])
.filter((c) => { .filter((c) => {
const id = parseInt(c.databaseId); const id = parseInt(c.databaseId)
return id !== commentId && id !== payload.comment.id; return id !== commentId && id !== payload.comment.id
}) })
.map((c) => ` - ${c.author.login} at ${c.createdAt}: ${c.body}`); .map((c) => ` - ${c.author.login} at ${c.createdAt}: ${c.body}`)
const files = (pr.files.nodes || []).map( const files = (pr.files.nodes || []).map((f) => ` - ${f.path} (${f.changeType}) +${f.additions}/-${f.deletions}`)
(f) => ` - ${f.path} (${f.changeType}) +${f.additions}/-${f.deletions}`
);
const reviewData = (pr.reviews.nodes || []).map((r) => { const reviewData = (pr.reviews.nodes || []).map((r) => {
const comments = (r.comments.nodes || []).map( const comments = (r.comments.nodes || []).map((c) => ` - ${c.path}:${c.line ?? "?"}: ${c.body}`)
(c) => ` - ${c.path}:${c.line ?? "?"}: ${c.body}`
);
return [ return [
` - ${r.author.login} at ${r.submittedAt}:`, ` - ${r.author.login} at ${r.submittedAt}:`,
` - Review body: ${r.body}`, ` - Review body: ${r.body}`,
...(comments.length > 0 ? [" - Comments:", ...comments] : []), ...(comments.length > 0 ? [" - Comments:", ...comments] : []),
]; ]
}); })
return [ return [
"Here is the context for the pull request:", "Here is the context for the pull request:",
@@ -572,11 +524,11 @@ function buildPromptDataForPR(pr: GitHubPullRequest) {
...(comments.length > 0 ? ["- Comments:", ...comments] : []), ...(comments.length > 0 ? ["- Comments:", ...comments] : []),
...(files.length > 0 ? ["- Changed files:", ...files] : []), ...(files.length > 0 ? ["- Changed files:", ...files] : []),
...(reviewData.length > 0 ? ["- Reviews:", ...reviewData] : []), ...(reviewData.length > 0 ? ["- Reviews:", ...reviewData] : []),
].join("\n"); ].join("\n")
} }
async function revokeAppToken() { async function revokeAppToken() {
if (!appToken) return; if (!appToken) return
await fetch("https://api.github.com/installation/token", { await fetch("https://api.github.com/installation/token", {
method: "DELETE", method: "DELETE",
@@ -585,5 +537,5 @@ async function revokeAppToken() {
Accept: "application/vnd.github+json", Accept: "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28", "X-GitHub-Api-Version": "2022-11-28",
}, },
}); })
} }
+8 -7
View File
@@ -49,12 +49,15 @@ resources:
models: models:
app: App app: App
logLevel: LogLevel logLevel: LogLevel
provider: Provider
model: Model
mode: Mode mode: Mode
methods: methods:
get: get /app get: get /app
init: post /app/init init: post /app/init
log: post /log log: post /log
modes: get /mode modes: get /mode
providers: get /config/providers
find: find:
models: models:
@@ -75,15 +78,13 @@ resources:
config: config:
models: models:
config: Config config: Config
keybinds: KeybindsConfig keybindsConfig: KeybindsConfig
mcpLocal: McpLocalConfig mcpLocalConfig: McpLocalConfig
mcpRemote: McpRemoteConfig mcpRemoteConfig: McpRemoteConfig
mode: ModeConfig modeConfig: ModeConfig
provider: Provider layoutConfig: LayoutConfig
model: Model
methods: methods:
get: get /config get: get /config
providers: get /config/providers
session: session:
models: models: