Compare commits
5
Commits
v1.3.7
..
ba9fddad9d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba9fddad9d | ||
|
|
b4ab44eb3c | ||
|
|
693589c21c | ||
|
|
0cf63d64b6 | ||
|
|
1c48fab124 |
@@ -18,7 +18,7 @@ jobs:
|
|||||||
- name: Install Bun
|
- name: Install Bun
|
||||||
uses: https://github.com/oven-sh/setup-bun@v2
|
uses: https://github.com/oven-sh/setup-bun@v2
|
||||||
with:
|
with:
|
||||||
bun-version: "1.3.14"
|
bun-version: "1.4.2"
|
||||||
- name: Verify and build
|
- name: Verify and build
|
||||||
run: |
|
run: |
|
||||||
bun install --frozen-lockfile
|
bun install --frozen-lockfile
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
- name: Install Bun
|
- name: Install Bun
|
||||||
uses: https://github.com/oven-sh/setup-bun@v2
|
uses: https://github.com/oven-sh/setup-bun@v2
|
||||||
with:
|
with:
|
||||||
bun-version: "1.3.14"
|
bun-version: "1.4.2"
|
||||||
- name: Verify and build
|
- name: Verify and build
|
||||||
run: |
|
run: |
|
||||||
bun install --frozen-lockfile
|
bun install --frozen-lockfile
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ stanp-opencode is an OpenCode V2 coordinator with specialist workers for fast, g
|
|||||||
|
|
||||||
## Install the latest release
|
## Install the latest release
|
||||||
|
|
||||||
Requires OpenCode V2 2.0.2 (`opencode2`), Bun 1.3.14+, Bash, curl, jq, and `sha256sum` on Linux or WSL.
|
Requires OpenCode 2.0.4, Bun 1.4.2+, Bash, curl, jq, and `sha256sum` on Linux or WSL.
|
||||||
|
|
||||||
Run the installer without sudo:
|
Run the installer without sudo:
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ Rerun the command to upgrade to the latest published release.
|
|||||||
|
|
||||||
## Install from a local checkout
|
## Install from a local checkout
|
||||||
|
|
||||||
This requires Bash, jq, and Bun 1.3.14+:
|
This requires Bash, jq, and Bun 1.4.2+:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bash /path/to/stanp-opencode/install-local.sh
|
bash /path/to/stanp-opencode/install-local.sh
|
||||||
@@ -32,7 +32,7 @@ Add `--playwright` to this command to enable automatic Playwright MCP configurat
|
|||||||
|
|
||||||
The script installs dependencies and builds the checkout before installing it.
|
The script installs dependencies and builds the checkout before installing it.
|
||||||
|
|
||||||
After either installation, restart `opencode2` or run `opencode2 service restart` for an existing service. Connect OpenAI and select `coordinate`. The required models must be available for the workers to run.
|
After either installation, restart `opencode` or run `opencode service restart` for an existing service. Connect OpenAI and select `coordinate`. The required models must be available for the workers to run.
|
||||||
|
|
||||||
Both installers use `~/.config/opencode`, respect `XDG_CONFIG_HOME`, and accept `OPENCODE_CONFIG_DIR` as an override.
|
Both installers use `~/.config/opencode`, respect `XDG_CONFIG_HOME`, and accept `OPENCODE_CONFIG_DIR` as an override.
|
||||||
|
|
||||||
|
|||||||
@@ -5,25 +5,25 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "stanp-opencode",
|
"name": "stanp-opencode",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"zod": "4.1.8",
|
"zod": "4.6.5",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@opencode/client": "2.0.2",
|
"@opencode/client": "2.0.4",
|
||||||
"@opencode/plugin": "2.0.2",
|
"@opencode/plugin": "2.0.4",
|
||||||
"@opencode/schema": "2.0.2",
|
"@opencode/schema": "2.0.4",
|
||||||
"@opentui/core": "0.5.10",
|
"@opentui/core": "0.5.11",
|
||||||
"@opentui/solid": "0.5.10",
|
"@opentui/solid": "0.5.11",
|
||||||
"@oxlint/plugins": "1.82.0",
|
"@oxlint/plugins": "1.83.0",
|
||||||
"@types/bun": "1.3.14",
|
"@types/bun": "1.4.2",
|
||||||
"oxfmt": "0.67.0",
|
"oxfmt": "0.68.0",
|
||||||
"oxlint": "1.82.0",
|
"oxlint": "1.83.0",
|
||||||
"solid-js": "1.9.15",
|
"solid-js": "1.9.15",
|
||||||
"typescript": "7.0.2",
|
"typescript": "7.0.2",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@opencode/plugin": "2.0.2",
|
"@opencode/plugin": "2.0.4",
|
||||||
"@opentui/core": ">=0.5.10",
|
"@opentui/core": ">=0.5.11",
|
||||||
"@opentui/solid": ">=0.5.10",
|
"@opentui/solid": ">=0.5.11",
|
||||||
"solid-js": ">=1.9.0",
|
"solid-js": ">=1.9.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -201,17 +201,17 @@
|
|||||||
|
|
||||||
"@npmcli/run-script": ["@npmcli/run-script@10.0.4", "", { "dependencies": { "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "node-gyp": "^12.1.0", "proc-log": "^6.0.0" } }, "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg=="],
|
"@npmcli/run-script": ["@npmcli/run-script@10.0.4", "", { "dependencies": { "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "node-gyp": "^12.1.0", "proc-log": "^6.0.0" } }, "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg=="],
|
||||||
|
|
||||||
"@opencode/ai": ["@opencode/ai@2.0.2", "", { "dependencies": { "@aws-sdk/credential-providers": "3.1057.0", "@opencode/schema": "2.0.2", "@smithy/eventstream-codec": "4.2.14", "@smithy/util-utf8": "4.2.2", "aws4fetch": "1.0.20", "effect": "4.0.0-rc.112", "google-auth-library": "10.5.0" } }, "sha512-Byq9c3kRdIl+AfGidPkd3JUC6DnjaNXGem77sAFRSxYwA0AMJMImPm+ua6ibnRqJ+6HlEq9JSh+Z1nQ8s8xzrQ=="],
|
"@opencode/ai": ["@opencode/ai@2.0.4", "", { "dependencies": { "@aws-sdk/credential-providers": "3.1057.0", "@opencode/schema": "2.0.4", "@smithy/eventstream-codec": "4.2.14", "@smithy/util-utf8": "4.2.2", "aws4fetch": "1.0.20", "effect": "4.0.0-rc.112", "google-auth-library": "10.5.0" } }, "sha512-T/2wTuhy/I1Wxdy/GdhtMqugpl1OWKgVp+8A45mtS1jDrTSeHq2x5YhkComkJZ6BwdG/OvU6afTGDPA7/vd4RA=="],
|
||||||
|
|
||||||
"@opencode/client": ["@opencode/client@2.0.2", "", { "dependencies": { "@opencode/protocol": "2.0.2", "@opencode/schema": "2.0.2" }, "peerDependencies": { "effect": "4.0.0-rc.112", "solid-js": ">=1.9.0" }, "optionalPeers": ["effect", "solid-js"] }, "sha512-w8rrSsxY9qnuFrsQAHdLDE6mrEqUKQeo7fNsw2i/tFtimgspT53/8/3ckEVRuRUM5k6v68KiU2deG0W2gEIVDQ=="],
|
"@opencode/client": ["@opencode/client@2.0.4", "", { "dependencies": { "@opencode/protocol": "2.0.4", "@opencode/schema": "2.0.4" }, "peerDependencies": { "effect": "4.0.0-rc.112", "solid-js": ">=1.9.0" }, "optionalPeers": ["effect", "solid-js"] }, "sha512-GBFWT2os+gEtGXpHRvDUNkf0H9x9njDUVbUvvc4drH2CuAihVcHqdi9Wm4UiwkBrSLjrKPs4U1NJBh2Z7/x4tQ=="],
|
||||||
|
|
||||||
"@opencode/plugin": ["@opencode/plugin@2.0.2", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@opencode/ai": "2.0.2", "@opencode/client": "2.0.2", "@opencode/protocol": "2.0.2", "@opencode/schema": "2.0.2", "@opencode/util": "2.0.2", "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112", "zod": "4.1.8" }, "peerDependencies": { "@opencode/theme": "2.0.2", "@opentui/core": ">=0.5.10", "@opentui/solid": ">=0.5.10", "solid-js": ">=1.9.0" }, "optionalPeers": ["@opencode/theme", "@opentui/core", "@opentui/solid", "solid-js"] }, "sha512-lFXcsyg1fhzCpzuMqBhb2yNddMeynXZwXL3aHs1T9ftbFu4buFAdtE9ox09Q+CL/r7yGbbX4mdtjKYdnt0dn5Q=="],
|
"@opencode/plugin": ["@opencode/plugin@2.0.4", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@opencode/ai": "2.0.4", "@opencode/client": "2.0.4", "@opencode/protocol": "2.0.4", "@opencode/schema": "2.0.4", "@opencode/util": "2.0.4", "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112", "zod": "4.1.8" }, "peerDependencies": { "@opencode/theme": "2.0.4", "@opentui/core": ">=0.5.10", "@opentui/solid": ">=0.5.10", "solid-js": ">=1.9.0" }, "optionalPeers": ["@opencode/theme", "@opentui/core", "@opentui/solid", "solid-js"] }, "sha512-NsC1STARfXxe+ZoXjXzpxvtS9l4h9Aen8ZccaCd1d9+1eyYdp+q8DU3Rxh7Ch0jiwiQMybS2Z+KgAfZJBnTBbA=="],
|
||||||
|
|
||||||
"@opencode/protocol": ["@opencode/protocol@2.0.2", "", { "dependencies": { "@opencode/schema": "2.0.2", "effect": "4.0.0-rc.112" } }, "sha512-FxTxdHPNz46NkG8ZBB2S60QzXbZDlVEyZ6KeYTt2G7hcWB5JlMYBh8jeqHlsLbquKinvMKA2iuEsA1NaccN+YQ=="],
|
"@opencode/protocol": ["@opencode/protocol@2.0.4", "", { "dependencies": { "@opencode/schema": "2.0.4", "effect": "4.0.0-rc.112" } }, "sha512-uWe2dmMouprSkfBu29XLR6GCWckkhm0YOo9ve07kTRqJCSoJzgQDF/8pouWG0cDCJ6oWj3bRQajXriBQyWSpUw=="],
|
||||||
|
|
||||||
"@opencode/schema": ["@opencode/schema@2.0.2", "", { "dependencies": { "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112" } }, "sha512-jF23H41j6zM2Az1pYLD6NFfzpoQ79CX0AxRkfNxTZFbPfjGGc+EPSOzVQP/r4Y/5bkSSqVga0Vn7MyoP8QhwDQ=="],
|
"@opencode/schema": ["@opencode/schema@2.0.4", "", { "dependencies": { "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112" } }, "sha512-UyGcCsRb2hTH98rnBqfJogFve8kJsIbsEreRxqhkBIEGrtDTqcUd5NnqB7qlJp2khesMvpOH0GmCHlgz44C+uQ=="],
|
||||||
|
|
||||||
"@opencode/util": ["@opencode/util@2.0.2", "", { "dependencies": { "@effect/opentelemetry": "4.0.0-rc.112", "@effect/platform-node": "4.0.0-rc.112", "@effect/platform-node-shared": "4.0.0-rc.112", "@npmcli/arborist": "9.4.0", "@npmcli/config": "10.8.1", "@opentelemetry/api": "1.9.0", "@opentelemetry/context-async-hooks": "2.6.1", "@opentelemetry/exporter-trace-otlp-http": "0.214.0", "@opentelemetry/sdk-trace-base": "2.6.1", "@opentelemetry/sdk-trace-node": "2.6.1", "cross-spawn": "7.0.6", "effect": "4.0.0-rc.112", "glob": "13.0.5", "mime-types": "3.0.2", "minimatch": "10.2.5", "npm-package-arg": "13.0.2", "pacote": "21.5.1" } }, "sha512-AKnFr44s1Q7/Ud+Pl4QMCEJoIp33xyDiTi693BofXn+HBDHdJmKrwq87YpG+Kwt9t48gVv6Cx1glmqJ4lVJpHg=="],
|
"@opencode/util": ["@opencode/util@2.0.4", "", { "dependencies": { "@effect/opentelemetry": "4.0.0-rc.112", "@effect/platform-node": "4.0.0-rc.112", "@effect/platform-node-shared": "4.0.0-rc.112", "@npmcli/arborist": "9.4.0", "@npmcli/config": "10.8.1", "@opentelemetry/api": "1.9.0", "@opentelemetry/context-async-hooks": "2.6.1", "@opentelemetry/exporter-trace-otlp-http": "0.214.0", "@opentelemetry/sdk-trace-base": "2.6.1", "@opentelemetry/sdk-trace-node": "2.6.1", "cross-spawn": "7.0.6", "effect": "4.0.0-rc.112", "glob": "13.0.5", "mime-types": "3.0.2", "minimatch": "10.2.5", "npm-package-arg": "13.0.2", "pacote": "21.5.1" } }, "sha512-jo6zhWqJ4WaU+fUjM8/Ea4i06gxTQFEFgfq2XG9J8gSDUhfsj4l9wJ3cLtSuKFQGeUeWqJJwRgDhCW+rUbis6Q=="],
|
||||||
|
|
||||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||||
|
|
||||||
@@ -239,103 +239,103 @@
|
|||||||
|
|
||||||
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="],
|
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="],
|
||||||
|
|
||||||
"@opentui/core": ["@opentui/core@0.5.10", "", { "dependencies": { "bun-ffi-structs": "0.3.1", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.5.10", "@opentui/core-darwin-x64": "0.5.10", "@opentui/core-linux-arm64": "0.5.10", "@opentui/core-linux-arm64-musl": "0.5.10", "@opentui/core-linux-x64": "0.5.10", "@opentui/core-linux-x64-musl": "0.5.10", "@opentui/core-win32-arm64": "0.5.10", "@opentui/core-win32-x64": "0.5.10" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-C3a2UbmefeAjIxAgm4BqjuSxKT4oqutfvYFwVvUgMxmGRHkNbBc/s7sukV0JgwcxFcV3uMFrXxo+E+BQtvuOiw=="],
|
"@opentui/core": ["@opentui/core@0.5.11", "", { "dependencies": { "bun-ffi-structs": "0.3.1", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.5.11", "@opentui/core-darwin-x64": "0.5.11", "@opentui/core-linux-arm64": "0.5.11", "@opentui/core-linux-arm64-musl": "0.5.11", "@opentui/core-linux-x64": "0.5.11", "@opentui/core-linux-x64-musl": "0.5.11", "@opentui/core-win32-arm64": "0.5.11", "@opentui/core-win32-x64": "0.5.11" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-pImMfjCNx7JUp9Df1LRZBDLisWqgzOLXZKXO+hh3jA9ujBFPQnZOqbG+/N5uVAAX8IZGaqhYSQRwSZIFBmcfbQ=="],
|
||||||
|
|
||||||
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.5.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Vyb+nTbhab8ZcRy5gg1loEEGwRcIbjAeVRIBfHBcbFDqmITBOg7x2gqJ+x/TnoOy4uwMhCmICUN2wiyREw3r1Q=="],
|
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.5.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DRXY5ioq+n1ZNAMAcaFaBunr0cmi2gqucjbTW7lgFp8t9uN3fNZnLTDOqkCTQtT2XhrU4GXqySaPSQ4qFG/EAQ=="],
|
||||||
|
|
||||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.5.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-tTFLcM7Oj1gTyhm/bUdAt3C6grZdCxPk6+/g2azcZBUlI3/62LwbeRS6HbQKFFmm+1fUmX8cq6kWrtul885mVg=="],
|
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.5.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-yP/8GliJDiJNm8YYJKvgWuy6xyCEd8d4GwBVOIzCFOI7ZIbGP8GOTvmwIjRW4Paw20pTttWMWyRoQiCvOXvH2g=="],
|
||||||
|
|
||||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.5.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-ncJXcgudhBf2GdJyF3xVQN/Ec+1F7GOL+pRrURmgBYSj2v1w6EyoDQFAACtPTK2c3R38W6fvZwL4JSLlm4EFXQ=="],
|
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.5.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-zBIsRFHlLUYFNhapRSNt9dz4mC8gZ4Wxcfy3A+2AwqsgCipcr2FkIuAXYqN08q+IvqFX7DfqgIFGWDNedHTPUg=="],
|
||||||
|
|
||||||
"@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.5.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-dGMphDKexSdeYqwl0wgoFBP88Ta/cdi1Zc1mk29/ENkSCGz+74zlCHgqTHRNGLmI8W5TfuUtCyktQH11/Z+TBQ=="],
|
"@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.5.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-x+xeR2LYibvIi/qQetRjJR008sFRve60QuDcO8ItxUwzFeKTDzl5CEiZpBXfm5I4FhRNuyuj0TSPIFadMvrjFQ=="],
|
||||||
|
|
||||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.5.10", "", { "os": "linux", "cpu": "x64" }, "sha512-5qtYaOgwVycZD1GaGshTRsi0rXPAmVExO03N1JQaHu+NYxK/vXSOc7Bu4QW0sPXx3Sp0SpzpP+FHjXABfoK66g=="],
|
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.5.11", "", { "os": "linux", "cpu": "x64" }, "sha512-pSOXqOADrv+zINOgR3FDFA9zVRaim3zl8/yhtO+X9rEJ6f34z3gDund0Gf88hNJSMpZK5xWtipEVm28RY5VF8w=="],
|
||||||
|
|
||||||
"@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.5.10", "", { "os": "linux", "cpu": "x64" }, "sha512-Oj4H9hApuvuTKPWxh4SoZAgGJorR7vbvnrZA/cAkSMAk2VGSoHRRcqeXQbcH8IcdjVZ0KFpv8Zkl/D5Ye+2mew=="],
|
"@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.5.11", "", { "os": "linux", "cpu": "x64" }, "sha512-MyqOnSs8pTYG2xmFr1xt6xZIuHu2Xu4pkle9my9JdE+WClmusHf0YN9Eas6jQLAq5XUi34r22wMeK0juk93zyw=="],
|
||||||
|
|
||||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.5.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-A9VhgvTxQoUdZ+8LmUumEng1sQNbj9QQQT3NYG9mSxI54qTANi7vOWNSphMiY6RMVsr22pgm6nUvSSvJXv7Jog=="],
|
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.5.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-MGGRXIDJ//HyaqC5ndSr7/CUl+ICdYEAMcjbA00UWsthh4ZO/rYhPkyqOaTn5ck6+G4ca3/+M76J+jImMYTjNg=="],
|
||||||
|
|
||||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.5.10", "", { "os": "win32", "cpu": "x64" }, "sha512-u3KHa7kEeWrmKVDRJYpxSGO+g5E9cMGlrmTsPN3GVPHUmQMiREUawLXUvsU8+IHaQnqG3Q5nuE1yf4fPBzS+Qw=="],
|
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.5.11", "", { "os": "win32", "cpu": "x64" }, "sha512-sMEGX9rhiPd1gBa190jzj5uIdzKCMImxHmr22hJLxIRWqejxWvqGnRBkW68wT8NfMViDiMtZWavgWL7GgmYCAQ=="],
|
||||||
|
|
||||||
"@opentui/solid": ["@opentui/solid@0.5.10", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.10", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-KrmMIsHiKBHOABTC0brOwqWm+sGq1ZX2sGCAx6WgtBbE3STMup9n8TAy/6gUYhwcjC9zugT53ytfSVwCwVWZUg=="],
|
"@opentui/solid": ["@opentui/solid@0.5.11", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.11", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-u8RJ4UMwzi+r9M1sopZdnT+7XFSHmLzVmhPhc6N2LfBrA9Db4lZ9sQA+ywgdSDkzdANpAOwGLNUQlY/F1OOCLA=="],
|
||||||
|
|
||||||
"@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.67.0", "", { "os": "android", "cpu": "arm" }, "sha512-2olh3ioEmc4gRzQm7jxyB1b/PFBoFvTq8KdgYySeNpysDtA6DEg2Mvya4/I6flhL7G0eOrE8RD7JCNCIMhE16Q=="],
|
"@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.68.0", "", { "os": "android", "cpu": "arm" }, "sha512-dhfYPbzv/h9JgHjNkl2R6sOjUfxDyLGOZVb3g8/ScaTNwwJcYgmHh8kcYFDUhinuy1QAoANCWUvw1jlk+z6gAg=="],
|
||||||
|
|
||||||
"@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.67.0", "", { "os": "android", "cpu": "arm64" }, "sha512-ulfw8EHN1MBq/MFFDXw2/M1VAFu5mRUcnuZ8Hqbv9viAnFzO9t1jKSAsDqKYYDGMlytF/uj6Z5z5n/tHupnKhw=="],
|
"@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.68.0", "", { "os": "android", "cpu": "arm64" }, "sha512-v3Njdi6qY0O/5eGfg01ww2w6gTn2mUvZ72Bnx1/UN53A9wruh3Nk6otc3WkgJLkXD4Qgz1SOcVQieH1oD03V9Q=="],
|
||||||
|
|
||||||
"@oxfmt/binding-darwin-arm64": ["@oxfmt/binding-darwin-arm64@0.67.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MfONZx/O2o9M5v2jDFol556G9+A+P9xCuJ4DZ+qhE+RnaCdoscy6Eu5nq1dbuNxhwdJyZ6kLI7fnG9mwEeOeGg=="],
|
"@oxfmt/binding-darwin-arm64": ["@oxfmt/binding-darwin-arm64@0.68.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ei4MCMzHFREmZwPJ7KuWUB4kBuHdsgDrnXGJVcEAopU7fj7S42I8BChdFILWdHvhFqR08FLJtOfbZIr2CDw0cA=="],
|
||||||
|
|
||||||
"@oxfmt/binding-darwin-x64": ["@oxfmt/binding-darwin-x64@0.67.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-CYnIx5LvFVJnyJcCqwH2jxMKjFjqo5678MPjdmNFoSGMhlOvZ/xRZqvhDcolKrXc8fezW3AKh+C4wyoFuWOSSg=="],
|
"@oxfmt/binding-darwin-x64": ["@oxfmt/binding-darwin-x64@0.68.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-UrKgzZxYhwB9DSvTX+vdgl9M32wLUNKJcAKIoiyx/Kzn/zveqi7W6kYVcRroFMhS3Kwz0KhTk3WBeSuQn4YCTg=="],
|
||||||
|
|
||||||
"@oxfmt/binding-freebsd-x64": ["@oxfmt/binding-freebsd-x64@0.67.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-7/iF1orvIS9mxhKUqnmtMgm+OrSQ5acPwuvdQrm6ECgqbwPmC+Pw9cdke3sNfVN6pT2hbJ58+jP8BCThl5HXOg=="],
|
"@oxfmt/binding-freebsd-x64": ["@oxfmt/binding-freebsd-x64@0.68.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-6jrEKgpJbilM1QaRv7hEtKXr4p4AK4jvvyOtajwyhu0kOz3e0O7OLnSTk6tBotRqCcUC4ehZRJ1Zx+Y99wieLw=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-arm-gnueabihf": ["@oxfmt/binding-linux-arm-gnueabihf@0.67.0", "", { "os": "linux", "cpu": "arm" }, "sha512-yy+OGys07IZOpOmYPZoObKyUQLkfxeQqeCypk+1jaZd8HGo77hzvU1Jg8X3+W75o+9lszOjBfg0nkGtlwYywXw=="],
|
"@oxfmt/binding-linux-arm-gnueabihf": ["@oxfmt/binding-linux-arm-gnueabihf@0.68.0", "", { "os": "linux", "cpu": "arm" }, "sha512-YOIVnKOBaLeGullskS179N12hjSAdFYnzLjOaKiLhAKNWgnShq9w4xRdtmUm6BlnP65l2/EA9Aw/KlftNxDM7Q=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-arm-musleabihf": ["@oxfmt/binding-linux-arm-musleabihf@0.67.0", "", { "os": "linux", "cpu": "arm" }, "sha512-wPIeeigXgJpwNw3wydYRt3U9iN9Y/ejpOZuYL9IA7igxWs7LIQMOkhKxTumRvy6dIv0iXKk3RTw3Vmjg0i+2sg=="],
|
"@oxfmt/binding-linux-arm-musleabihf": ["@oxfmt/binding-linux-arm-musleabihf@0.68.0", "", { "os": "linux", "cpu": "arm" }, "sha512-xW5XoEHVNqydPBv2KXvk9lmEzyAlOQHVEazKoXUuAacqekjya+OdiaFjjEBl0oJD02raG8g3TRl9OVCh9PDIHA=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-arm64-gnu": ["@oxfmt/binding-linux-arm64-gnu@0.67.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0+XNxcdbkTfxdcD4qW6Ci9n+mBNJ8xTBumnxKvKBmRFOdx0Wf8/KiHjCJayooXmYkqRpRVd98Q5egvzx5BLSgQ=="],
|
"@oxfmt/binding-linux-arm64-gnu": ["@oxfmt/binding-linux-arm64-gnu@0.68.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-QCvYwVVQieu6oyJglAgV9vH/YMDxZyR4cwVSYtoq9oOXd5N+D3TDUBjNwxFrLn5AdcJZOcvn/7IB17vJGp+2Og=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-arm64-musl": ["@oxfmt/binding-linux-arm64-musl@0.67.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-I75LKPJyNOYUzkqAiAMIE31+Ye7xtQXZdoty1IXn4B+bw5Zpmez5wfG19ejGpNnS/BzQ7LFS+7jxuTPb+vHiZw=="],
|
"@oxfmt/binding-linux-arm64-musl": ["@oxfmt/binding-linux-arm64-musl@0.68.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-4TVz5iFQ8ndrHnhX50UXiz9BIWAtUSOHJ6Nus4qWFfJBXq/Ed/krXbF/ehJu42BXM5tIvBs99jNIM22s9agY5A=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-ppc64-gnu": ["@oxfmt/binding-linux-ppc64-gnu@0.67.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-c2M5iRpe1QMZSRE/UvZoPdXBWb5Ic/ycvOyNiKCqPwQ/OyOKIMiJs02ynlNnjb7ZZJnRXYLmGcohoINOcwDK3w=="],
|
"@oxfmt/binding-linux-ppc64-gnu": ["@oxfmt/binding-linux-ppc64-gnu@0.68.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-qLe3ao0RP84bnPxBvRI+GnlK/jybo538NWu0Xrm+zYeTmJtpzqLhnnd5BH21NafqKnplbGZjtN1cnrOlWF73lw=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-riscv64-gnu": ["@oxfmt/binding-linux-riscv64-gnu@0.67.0", "", { "os": "linux", "cpu": "none" }, "sha512-dQzzYlV24Udhfm5ECuSdgqRvFJU/CGHzcYYEO3dLM6W6+CHiBFrq9OjIllkdCcPhsoSQ8o223Dja84MOSzed9A=="],
|
"@oxfmt/binding-linux-riscv64-gnu": ["@oxfmt/binding-linux-riscv64-gnu@0.68.0", "", { "os": "linux", "cpu": "none" }, "sha512-Yvyl7a6gbb0vM6r925KW2dO+/CmXySO5TVbcX7o/uZJ+d108HFOG0TxIyHApmn5USuj5mhDPxzhiVwOlGP7uSA=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-riscv64-musl": ["@oxfmt/binding-linux-riscv64-musl@0.67.0", "", { "os": "linux", "cpu": "none" }, "sha512-rFNq1CgX4qMJANOq42LkAs90JE80GpiaEohAV2qn/gT2hGjQTW1zBO5zQBxArI4926pM1OSzo3CN0tBszGBIaA=="],
|
"@oxfmt/binding-linux-riscv64-musl": ["@oxfmt/binding-linux-riscv64-musl@0.68.0", "", { "os": "linux", "cpu": "none" }, "sha512-mJlFuFVCxzrYM5sFStN433D/s/mb6Wq4aCQAM02vs/OudHywnaSAd2rb1vlYUJtqdYIciJtiasuxvfbYkv5fLg=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-s390x-gnu": ["@oxfmt/binding-linux-s390x-gnu@0.67.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-Sky6rEdz2o5IGq01lPhS12yEvDdChVEcaYrcLHkveh4Fx0qPjljE/Iul6SX/bRMl6lNc8J7J/mDQdzgBdA++Pg=="],
|
"@oxfmt/binding-linux-s390x-gnu": ["@oxfmt/binding-linux-s390x-gnu@0.68.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-RlfSg++qs1hbKltRR6lYvV9EoI3MdlfSQD9w1hdHVYjHqjIn1tkH4FWOpMSmjKGN20zr+nI+W9o4ARogCDudGQ=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-x64-gnu": ["@oxfmt/binding-linux-x64-gnu@0.67.0", "", { "os": "linux", "cpu": "x64" }, "sha512-vPXmlNORV8AZq2Ocxh07pxwMjfENUWCV/eZArnao0qC3NO/hDeTVkQvee7SJJUbIiF5PZbBa4kYmaXnu7Rk58w=="],
|
"@oxfmt/binding-linux-x64-gnu": ["@oxfmt/binding-linux-x64-gnu@0.68.0", "", { "os": "linux", "cpu": "x64" }, "sha512-nyzRB9U+dlYUKu3pMo3afHzZBUv/oTHZMG36ZfJViNVfOIzp70Q4GS8FFRGgYJ/p0zcyDCgpBvYISOdJOMh+jQ=="],
|
||||||
|
|
||||||
"@oxfmt/binding-linux-x64-musl": ["@oxfmt/binding-linux-x64-musl@0.67.0", "", { "os": "linux", "cpu": "x64" }, "sha512-x/WAtFqYtVr3vZ9ni8nr4kn9whSitg8fOljq/pZzBpxopRdY1BMLZCZkrbIbaBcYkm46qGbqVea2FCWmtQ2P9w=="],
|
"@oxfmt/binding-linux-x64-musl": ["@oxfmt/binding-linux-x64-musl@0.68.0", "", { "os": "linux", "cpu": "x64" }, "sha512-iCx3sbZRIvGrL1RafphEiUKBaW1lc0/tAjKOIB/Wjw2+STRBEdu5+fH1Gc1faEWEmc2k5Ks4iUUV54Zd5C9a1A=="],
|
||||||
|
|
||||||
"@oxfmt/binding-openharmony-arm64": ["@oxfmt/binding-openharmony-arm64@0.67.0", "", { "os": "none", "cpu": "arm64" }, "sha512-eRw9Neh4/aA6i+q/R3WU1gGQINhVM0J4fXIm6t27caOamkr/37uAkp1IdBx4zlJH97hmXR63z/q9n5c5dN7MzA=="],
|
"@oxfmt/binding-openharmony-arm64": ["@oxfmt/binding-openharmony-arm64@0.68.0", "", { "os": "none", "cpu": "arm64" }, "sha512-x2X5AZez7OgyLLFpwIgItoXBUqudDM7yiaTsxv8R8vKQ6e81l0jVw0NFeUCXzcl1sAJq8h+tC8N4mY8EiMeL4w=="],
|
||||||
|
|
||||||
"@oxfmt/binding-win32-arm64-msvc": ["@oxfmt/binding-win32-arm64-msvc@0.67.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-YIMvb+sGNYN2uc6+QK2HLPeEKM2vl7QZ5onQzpAJRb6pnf0DwUFP5R8tdS9R0l8hdUil2gu4Uxd0Yxrop0iT4w=="],
|
"@oxfmt/binding-win32-arm64-msvc": ["@oxfmt/binding-win32-arm64-msvc@0.68.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-AHVPjXkenLPQUh6kB8zSC8pX2ct9r4T1Edk9r/RNJyov6wPsS5uAfYtipwG4chn6+3bPFG5rI/3DxEeH8vib1w=="],
|
||||||
|
|
||||||
"@oxfmt/binding-win32-ia32-msvc": ["@oxfmt/binding-win32-ia32-msvc@0.67.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-LzmU9MyACPzwNDIK0ItMedHPz735Ug7ELWguxo4/kuy6zWuDoeglOAEFCY8jLg0PzRpFO3hDyLFe2Gu2eFDeGA=="],
|
"@oxfmt/binding-win32-ia32-msvc": ["@oxfmt/binding-win32-ia32-msvc@0.68.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-n09SjEk5VH7z8Hl4WVP7hho+cCwGViENkQFiM45vbW85dJd7kEhWaHRUobaPzEmrWyu6uumd4EuNfNyDKLtzDA=="],
|
||||||
|
|
||||||
"@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.67.0", "", { "os": "win32", "cpu": "x64" }, "sha512-sbQOIDNLUEeVZcAJcSL5VURn7kfjvilPviody4Yl5n8lQCDtUm+C9oHTTwZS/m4d/Z6Vv3jNEiAofH932NPPCg=="],
|
"@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.68.0", "", { "os": "win32", "cpu": "x64" }, "sha512-gPe+dJLXaPuWPWqlpklDAJp0k+K9KhQPYiQLHfb+i2rmFuUGfJ/5Qlj6tr1mO6of5g0DiLjG/XCFHIaPhotqqA=="],
|
||||||
|
|
||||||
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.82.0", "", { "os": "android", "cpu": "arm" }, "sha512-a3LB+C5Dsj5b/qtmG/mv5WrzuiXEpg1KF5nXWcEvaoN5TYAqkIvxPOwTPp3Jy/FoGpRo8zsTFhMElMXfeoOEzA=="],
|
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.83.0", "", { "os": "android", "cpu": "arm" }, "sha512-0yGY24EwsLk5YDe6F+VkmZyRHSwJDALa3nIrPpq7FXmp2lV2d0TzvBCGeZk+wgiULRGr5blhyr4QMp5KCXJUqA=="],
|
||||||
|
|
||||||
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.82.0", "", { "os": "android", "cpu": "arm64" }, "sha512-OBlhRgNqFblGpGenno/aqOfJLOkQ2B8Ig3iDAalfn0H8hJGZKXPeexCRTDm6uwv6YUjSA9Xnwt1y/Bgj5ZH8uw=="],
|
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.83.0", "", { "os": "android", "cpu": "arm64" }, "sha512-hHfJ0vc17A4iUjH5p9BsTUPYbYRNxGpvD2lbu1aBRk54bzNIx9o5TtYF39QPZcV95DagZd+4DEAw2RH3G2ZsMg=="],
|
||||||
|
|
||||||
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.82.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-dsopxqtY5ZdyT9uLHyGt1SyiLop6hi7hWI3PKpePodkRQOkLaCm+OE4fR9CAz9qdfjiFO8531tX/QDyP/psjFg=="],
|
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.83.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hsOjYjszLb/3zym/TkzUMPAoQlTJcuzSyEPOAyA+skXJIX9M0o+4JfOtqopX/Vf4hSLrJ98j0nvFo23gzk8auQ=="],
|
||||||
|
|
||||||
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.82.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-94Lu0SgTClKColU66g1VDuigV3HkcbkJBnTtZjGYfE8UPugaWDgKrm2icjC6HJVUYler2OXaHP/X0TBy8+CowQ=="],
|
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.83.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-mjh5oH2EA+wl5yRJYT9K9G61O2zFlpuv+yf2JwZOi0+dq2FnTUtm1h8i+5Ik0fXPWIu/k84I1psZR9aQsLAnyA=="],
|
||||||
|
|
||||||
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.82.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-hne/V06ewhh1i0w8+l7GDNROAGCGPmyFuOwiP7YTRu0JycyStJ4785dmF8xU5p0uUwt2emvIF9vc7Xjis+cJ0g=="],
|
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.83.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fNHr64/YaO8YssuoDVC8+F4Uk5enR86q5uxfHkQrjAPs1dbAILOrD2uaud+J7MO8Fx774g44ERLD0IGIvZE48w=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.82.0", "", { "os": "linux", "cpu": "arm" }, "sha512-aWY2xtbZf1LneW9Qsv/n2Sp8gOu74JrlQzEtj4coHX2SHFrCfhmAumaU+sI/A5nr+yoTRTSmI/pL2s6ADlNSkw=="],
|
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.83.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Qpwy3zzAwMj+8/lyYItHmkSMwbkprFNWTK7jPYDOxSyxEhaSLOWYUTCMkjF334J8/WD0nznCCsoBbIH6hpsuIw=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.82.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Fe+TtXCXMh/5f7kWlZ2VAwsMumZWtraFlKVk1NJlL52/beGwfDE7ov+/8gVirHzWokzGu7X65hSPq0ucPDskWQ=="],
|
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.83.0", "", { "os": "linux", "cpu": "arm" }, "sha512-s+BirYLFq7JL2k9sP0XI3ZXJ9dYvJ8sX3jLCLoag7tt+zrSHpZxP0jqznfL+Gdgwu7ay0dYgGYJXrQvq3iWloA=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.82.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-6azCZ6OJudlvipNttXCCQcyeFfcJ/NvUZdSN1z8elo73kCHtyQC7WTiUcSjWYvJ1jaq9KDUyMAoAS/vNzhBomA=="],
|
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.83.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-7lihXt3vKr+GIyapNbHrnFHm/biiW30le6Zv/DExbAFPF6YwCQXVFlONPFehxs0CpGO4CBfYPM9rdDT+XMoIlg=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.82.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-PLEaSD8IAIIlwW4dwOd9YaxuxeOpwiXL4J24rcnE4iNtyM5j9Q9/3+gti08oXpx0u2ygNjRDx9xjWWpQonuJEw=="],
|
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.83.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-q63JalLYVkZiZvls1z3PPUnpmQluOMXp0khqQMznCeAPLGydfNY8JhvuA4WlK57JfrvikU8wB5lPVveqpIXvew=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.82.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-D94em/BwknNTn4vqxjHh5wb2oL566eFhArabqKIr0cNZMHOJuiraFp1A8tXpH05bbE5tqwEfLXTI0MWEGtn3Dw=="],
|
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.83.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-krQmDF+dRbxvdqVPV88ZuOoPPu8X5BuqDA8Hd+qcS4YMRQCb+nexA57DazgGsc/rGdKBe3QmV0mnv0bdpW/p5g=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.82.0", "", { "os": "linux", "cpu": "none" }, "sha512-MOprxBaoYU2D4VgxXCl3ghydThWtx7Um1lL51kGYNeQ5Al7WzsH7/tqGdNtbLrIWnjq3bsm13+nz/gRIxjrOXw=="],
|
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.83.0", "", { "os": "linux", "cpu": "none" }, "sha512-MmOl8Y6txEAXZU1RG8Rr264jQ6D7VPmqFsU/45x/FeWsGe32hklTqGrLE6UxHzp5Rjt0wP+20tY8YXKgSFB3mw=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.82.0", "", { "os": "linux", "cpu": "none" }, "sha512-5h55QsfJ/luDXZzC20k6SNOY1Az+dCP9WvntKtcUWh2JhckAdwApY2ZusaBTwLENnReXU+A2fJtSrYvZJNKNPg=="],
|
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.83.0", "", { "os": "linux", "cpu": "none" }, "sha512-u1rMymh0W3JZkq370kzQsYPULGWqhE09pZRqnZvUSoYaI9pVO5yVX+iYIslmWuEgwuzH9YAaOsScJiobWCHoOw=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.82.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-IE8NJNLlHr0CaXyGJPGVn0eTkUyoj1I2UfA8x7I4PSOYKsQ/6btVC7Pywrj5onk0cMH25r6Z38SoN3AvE5Zuog=="],
|
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.83.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-y0zK3HNwGysu7rqtE+BQG/d0bx5gh/KwlOtghN8oWeK1KcWzeaLqtZrbm8owqdma1lFyrce/hTO5ismuNu+INQ=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.82.0", "", { "os": "linux", "cpu": "x64" }, "sha512-XUUUxaBo9XKl+J1B9EmP1cTGQPddzeURvoGkfwh/94PGnbW+hBprDljneoI2M1jzC1bzrIV3ihc7iM9UXl8+tg=="],
|
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.83.0", "", { "os": "linux", "cpu": "x64" }, "sha512-rS5gM0NgD7ngmuJmbIehsidtrOwKkLFwCQbKEeb9KuyQrrWNq5Zkn0uV6AYdXOMJ0grrWEiLwBuvMxt8w5vsNw=="],
|
||||||
|
|
||||||
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.82.0", "", { "os": "linux", "cpu": "x64" }, "sha512-SWLSFulX9TDuH6yvbPYp4+VNn6jkkIvvI+KiujDM5rWBRHEfkesCC/pCneIIUr6ovkxZ5fRtpi2v5Cz5FrMJZg=="],
|
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.83.0", "", { "os": "linux", "cpu": "x64" }, "sha512-W2IH4EtpcPaWcvNGCA95YoDg4vxqE/ZiPCi3arrxEEpsK7+JQN9WYwrlYFx9pcdP6KPXqRqkv3zdQPHcx7b6YQ=="],
|
||||||
|
|
||||||
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.82.0", "", { "os": "none", "cpu": "arm64" }, "sha512-BQy35f6ZUdNr9a6c7B7orxQTcLjByGT2z3WAgmRovpRwmPYAaJ+NTplmMzhdjdJ4qSchfMNZy/Ukg+qRg6zseQ=="],
|
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.83.0", "", { "os": "none", "cpu": "arm64" }, "sha512-6LyKkUyoajssTPLlZmDbZIbu4IZ5B4bGuRUnBgCGpEvHP3FQMaYITncHA/unPUo7q+Z+pIu2HhdkQ+8d1SG7iA=="],
|
||||||
|
|
||||||
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.82.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-V4QhSTg5gctZue8RJjsGi7NpQPThr/p1/HfmiMC5kfe1KFEup9SQRVub4A6kijQjdHfxj7bLL1KO3QO7/5bwMQ=="],
|
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.83.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Uz/fObEtF0jmNJQJ8CGRBKfefYstS0/wjD3s6IGzP8nUwsJykHQJBiN3npHwKiGRGn/vvBEgNr4B3cCzmmatvg=="],
|
||||||
|
|
||||||
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.82.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-TUSCLaKB2yktpFAJ/r3HAUYsaV/3DT7JS4iNKyoh3a9YNwD0UG7Ezh4D8m23654vQcU6P/RQrCAjRPKe4peP/A=="],
|
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.83.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-u7XcvPW6Bk58tY5iWs2ESb0vJjoE/kuSpHxopbwp/p3ZtWVQXZ6wor5w3ssVTHOqd/v8b+QdhSFWQ4grEUNWpA=="],
|
||||||
|
|
||||||
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.82.0", "", { "os": "win32", "cpu": "x64" }, "sha512-VTVoRIWJTb+wvUX8EYoPArfFH02whuR10goFXE/LHRRX33ajRrFgqbcONXZMiF4C5rnattfkm87HqYn8jb8hmQ=="],
|
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.83.0", "", { "os": "win32", "cpu": "x64" }, "sha512-LZRubd7ph13QmAg4fFecTYVZkiYbROR2Htaxh/ufWRkDhPOm2wrwaEYR89e0YpPFD3dqBrPoxS7myBw5hmYA7Q=="],
|
||||||
|
|
||||||
"@oxlint/plugins": ["@oxlint/plugins@1.82.0", "", {}, "sha512-IDF4UXBNOaCeLoEpVxf5Bg85KOWdeuBEkbo1rGzS2vXcbD+GT1asBSeeTC+5BgW6NFTHVByd6N5giHsFPGtwAA=="],
|
"@oxlint/plugins": ["@oxlint/plugins@1.83.0", "", {}, "sha512-qD64wr6SS1DL7YbJQ8WWjyUfFfrJsvAy9Vo0sG/PYUQy30w0uemN2h6j4xuvj4noyETDpzcGC20sv+FH7GrN5A=="],
|
||||||
|
|
||||||
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
||||||
|
|
||||||
@@ -407,7 +407,7 @@
|
|||||||
|
|
||||||
"@tufjs/models": ["@tufjs/models@4.1.0", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^10.1.1" } }, "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww=="],
|
"@tufjs/models": ["@tufjs/models@4.1.0", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^10.1.1" } }, "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww=="],
|
||||||
|
|
||||||
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
|
"@types/bun": ["@types/bun@1.4.2", "", { "dependencies": { "bun-types": "1.4.2" } }, "sha512-GimotNn7+ZV0uVArItBbriZsR1oNf0+WTzPkdcFrzShI7k2norL0uzEaJT8T33dWr7O/c9ZDuAFQrctKCi72oQ=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@26.5.0", "", { "dependencies": { "undici-types": "~8.9.0" } }, "sha512-dVSGpriSoCgz8WnDNTuSSuSv1PC/ALXihO4ulRZt7Md8k9mlbdin3lGOcDE8SnWOgf513ByWlXd7BK4azmyg/A=="],
|
"@types/node": ["@types/node@26.5.0", "", { "dependencies": { "undici-types": "~8.9.0" } }, "sha512-dVSGpriSoCgz8WnDNTuSSuSv1PC/ALXihO4ulRZt7Md8k9mlbdin3lGOcDE8SnWOgf513ByWlXd7BK4azmyg/A=="],
|
||||||
|
|
||||||
@@ -489,7 +489,7 @@
|
|||||||
|
|
||||||
"bun-ffi-structs": ["bun-ffi-structs@0.3.1", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-3gM7PpVWLyrwxWjcilSiGuhWanhZivvo6l0u573NziPH6f/gwk6McbaYgn7oJWov6pKGRTDbrg94W5DcJsKTtQ=="],
|
"bun-ffi-structs": ["bun-ffi-structs@0.3.1", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-3gM7PpVWLyrwxWjcilSiGuhWanhZivvo6l0u573NziPH6f/gwk6McbaYgn7oJWov6pKGRTDbrg94W5DcJsKTtQ=="],
|
||||||
|
|
||||||
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
"bun-types": ["bun-types@1.4.2", "", { "dependencies": { "@types/node": "*" } }, "sha512-bxV1FgK7yBIzjRe5zBozIM4Bem11ZJcCXSrjWRG3YWLt8yFDePu4cLjpebO8OvPeIE9trbyPF4fuj3Cia4Fj3w=="],
|
||||||
|
|
||||||
"cacache": ["cacache@20.0.4", "", { "dependencies": { "@npmcli/fs": "^5.0.0", "fs-minipass": "^3.0.0", "glob": "^13.0.0", "lru-cache": "^11.1.0", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^13.0.0" } }, "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA=="],
|
"cacache": ["cacache@20.0.4", "", { "dependencies": { "@npmcli/fs": "^5.0.0", "fs-minipass": "^3.0.0", "glob": "^13.0.0", "lru-cache": "^11.1.0", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^13.0.0" } }, "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA=="],
|
||||||
|
|
||||||
@@ -705,9 +705,9 @@
|
|||||||
|
|
||||||
"npm-registry-fetch": ["npm-registry-fetch@19.1.1", "", { "dependencies": { "@npmcli/redact": "^4.0.0", "jsonparse": "^1.3.1", "make-fetch-happen": "^15.0.0", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minizlib": "^3.0.1", "npm-package-arg": "^13.0.0", "proc-log": "^6.0.0" } }, "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw=="],
|
"npm-registry-fetch": ["npm-registry-fetch@19.1.1", "", { "dependencies": { "@npmcli/redact": "^4.0.0", "jsonparse": "^1.3.1", "make-fetch-happen": "^15.0.0", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minizlib": "^3.0.1", "npm-package-arg": "^13.0.0", "proc-log": "^6.0.0" } }, "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw=="],
|
||||||
|
|
||||||
"oxfmt": ["oxfmt@0.67.0", "", { "dependencies": { "tinypool": "2.1.2" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.67.0", "@oxfmt/binding-android-arm64": "0.67.0", "@oxfmt/binding-darwin-arm64": "0.67.0", "@oxfmt/binding-darwin-x64": "0.67.0", "@oxfmt/binding-freebsd-x64": "0.67.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.67.0", "@oxfmt/binding-linux-arm-musleabihf": "0.67.0", "@oxfmt/binding-linux-arm64-gnu": "0.67.0", "@oxfmt/binding-linux-arm64-musl": "0.67.0", "@oxfmt/binding-linux-ppc64-gnu": "0.67.0", "@oxfmt/binding-linux-riscv64-gnu": "0.67.0", "@oxfmt/binding-linux-riscv64-musl": "0.67.0", "@oxfmt/binding-linux-s390x-gnu": "0.67.0", "@oxfmt/binding-linux-x64-gnu": "0.67.0", "@oxfmt/binding-linux-x64-musl": "0.67.0", "@oxfmt/binding-openharmony-arm64": "0.67.0", "@oxfmt/binding-win32-arm64-msvc": "0.67.0", "@oxfmt/binding-win32-ia32-msvc": "0.67.0", "@oxfmt/binding-win32-x64-msvc": "0.67.0" }, "peerDependencies": { "svelte": "^5.0.0", "vite-plus": "*" }, "optionalPeers": ["svelte", "vite-plus"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-vV7sSiPsaO0mSxdoUdayipVDFPzW/UQ+hrezEHa20+Tx1dnMdZLSRHMT0PdS67FFbhd74M1n08asW21aLGeCrA=="],
|
"oxfmt": ["oxfmt@0.68.0", "", { "dependencies": { "tinypool": "2.1.2" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.68.0", "@oxfmt/binding-android-arm64": "0.68.0", "@oxfmt/binding-darwin-arm64": "0.68.0", "@oxfmt/binding-darwin-x64": "0.68.0", "@oxfmt/binding-freebsd-x64": "0.68.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.68.0", "@oxfmt/binding-linux-arm-musleabihf": "0.68.0", "@oxfmt/binding-linux-arm64-gnu": "0.68.0", "@oxfmt/binding-linux-arm64-musl": "0.68.0", "@oxfmt/binding-linux-ppc64-gnu": "0.68.0", "@oxfmt/binding-linux-riscv64-gnu": "0.68.0", "@oxfmt/binding-linux-riscv64-musl": "0.68.0", "@oxfmt/binding-linux-s390x-gnu": "0.68.0", "@oxfmt/binding-linux-x64-gnu": "0.68.0", "@oxfmt/binding-linux-x64-musl": "0.68.0", "@oxfmt/binding-openharmony-arm64": "0.68.0", "@oxfmt/binding-win32-arm64-msvc": "0.68.0", "@oxfmt/binding-win32-ia32-msvc": "0.68.0", "@oxfmt/binding-win32-x64-msvc": "0.68.0" }, "peerDependencies": { "svelte": "^5.0.0", "vite-plus": "*" }, "optionalPeers": ["svelte", "vite-plus"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-Z0XMofcXCGUXbcpBHnWyUiX93BGiw1B+lcHNbQDWEtOhX06ewoFfu4zXkyiLhRrNnMq0twqXRHUcJetf+GsiQQ=="],
|
||||||
|
|
||||||
"oxlint": ["oxlint@1.82.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.82.0", "@oxlint/binding-android-arm64": "1.82.0", "@oxlint/binding-darwin-arm64": "1.82.0", "@oxlint/binding-darwin-x64": "1.82.0", "@oxlint/binding-freebsd-x64": "1.82.0", "@oxlint/binding-linux-arm-gnueabihf": "1.82.0", "@oxlint/binding-linux-arm-musleabihf": "1.82.0", "@oxlint/binding-linux-arm64-gnu": "1.82.0", "@oxlint/binding-linux-arm64-musl": "1.82.0", "@oxlint/binding-linux-ppc64-gnu": "1.82.0", "@oxlint/binding-linux-riscv64-gnu": "1.82.0", "@oxlint/binding-linux-riscv64-musl": "1.82.0", "@oxlint/binding-linux-s390x-gnu": "1.82.0", "@oxlint/binding-linux-x64-gnu": "1.82.0", "@oxlint/binding-linux-x64-musl": "1.82.0", "@oxlint/binding-openharmony-arm64": "1.82.0", "@oxlint/binding-win32-arm64-msvc": "1.82.0", "@oxlint/binding-win32-ia32-msvc": "1.82.0", "@oxlint/binding-win32-x64-msvc": "1.82.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2001", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-+iFM1BGw1ntYJt3QngbJmjbrGxPaKMUADOXOijpWGnYcBPq8YZnQftSS1C+pVcDYy9YxqDVJKQqQkTazTQMboQ=="],
|
"oxlint": ["oxlint@1.83.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.83.0", "@oxlint/binding-android-arm64": "1.83.0", "@oxlint/binding-darwin-arm64": "1.83.0", "@oxlint/binding-darwin-x64": "1.83.0", "@oxlint/binding-freebsd-x64": "1.83.0", "@oxlint/binding-linux-arm-gnueabihf": "1.83.0", "@oxlint/binding-linux-arm-musleabihf": "1.83.0", "@oxlint/binding-linux-arm64-gnu": "1.83.0", "@oxlint/binding-linux-arm64-musl": "1.83.0", "@oxlint/binding-linux-ppc64-gnu": "1.83.0", "@oxlint/binding-linux-riscv64-gnu": "1.83.0", "@oxlint/binding-linux-riscv64-musl": "1.83.0", "@oxlint/binding-linux-s390x-gnu": "1.83.0", "@oxlint/binding-linux-x64-gnu": "1.83.0", "@oxlint/binding-linux-x64-musl": "1.83.0", "@oxlint/binding-openharmony-arm64": "1.83.0", "@oxlint/binding-win32-arm64-msvc": "1.83.0", "@oxlint/binding-win32-ia32-msvc": "1.83.0", "@oxlint/binding-win32-x64-msvc": "1.83.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2001", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-cyDzSzaw3uzP0TeCeq3lLRPPoaUxkbB4ZOXj+kn+5r+BX9V+4bNVGk9lxer+WrgcpebH4JxLlJ3KQjveVztOLQ=="],
|
||||||
|
|
||||||
"p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
|
"p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
|
||||||
|
|
||||||
@@ -851,7 +851,7 @@
|
|||||||
|
|
||||||
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
||||||
|
|
||||||
"zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="],
|
"zod": ["zod@4.6.5", "", {}, "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q=="],
|
||||||
|
|
||||||
"@aws-crypto/sha256-browser/@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/sha256-browser/@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=="],
|
||||||
|
|
||||||
@@ -879,6 +879,8 @@
|
|||||||
|
|
||||||
"@npmcli/promise-spawn/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="],
|
"@npmcli/promise-spawn/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="],
|
||||||
|
|
||||||
|
"@opencode/plugin/zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="],
|
||||||
|
|
||||||
"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=="],
|
||||||
|
|
||||||
"babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="],
|
"babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="],
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://opencode.ai/config.json",
|
"$schema": "https://opencode.ai/config.json",
|
||||||
// Use OpenCode V2 (opencode2), not the V1 opencode CLI.
|
// Requires OpenCode 2.0.4 or newer.
|
||||||
// Availability uses the native catalog, including integrations and earlier plugins.
|
// Availability uses the native catalog, including integrations and earlier plugins.
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -89,4 +89,4 @@ rm -rf "$backup"
|
|||||||
backup=""
|
backup=""
|
||||||
rm -f "$config/plugins/stanp-opencode.js"
|
rm -f "$config/plugins/stanp-opencode.js"
|
||||||
mv "$install/opencode.json" "$config_file"
|
mv "$install/opencode.json" "$config_file"
|
||||||
printf 'Built and installed stanp-opencode from %s into %s/plugins/stanp-opencode and updated %s\nRestart opencode2 to load it.\n' "$checkout" "$config" "$config_file"
|
printf 'Built and installed stanp-opencode from %s into %s/plugins/stanp-opencode and updated %s\nRestart opencode to load it.\n' "$checkout" "$config" "$config_file"
|
||||||
|
|||||||
+1
-1
@@ -100,4 +100,4 @@ fi
|
|||||||
rm -rf "$backup"
|
rm -rf "$backup"
|
||||||
rm -f "$config/plugins/stanp-opencode.js"
|
rm -f "$config/plugins/stanp-opencode.js"
|
||||||
mv "$install/opencode.json" "$config_file"
|
mv "$install/opencode.json" "$config_file"
|
||||||
printf 'Installed stanp-opencode %s into %s/plugins/stanp-opencode and updated %s\nRestart opencode2 to load it.\n' "$tag" "$config" "$config_file"
|
printf 'Installed stanp-opencode %s into %s/plugins/stanp-opencode and updated %s\nRestart opencode to load it.\n' "$tag" "$config" "$config_file"
|
||||||
|
|||||||
+15
-15
@@ -24,9 +24,9 @@
|
|||||||
"dist",
|
"dist",
|
||||||
"examples"
|
"examples"
|
||||||
],
|
],
|
||||||
"packageManager": "bun@1.3.14",
|
"packageManager": "bun@1.4.2",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.3.14"
|
"bun": ">=1.4.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"check": "tsc --noEmit",
|
"check": "tsc --noEmit",
|
||||||
@@ -37,25 +37,25 @@
|
|||||||
"build": "bun scripts/build.ts && tsc --project tsconfig.build.json --emitDeclarationOnly"
|
"build": "bun scripts/build.ts && tsc --project tsconfig.build.json --emitDeclarationOnly"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@opencode/client": "2.0.2",
|
"@opencode/client": "2.0.4",
|
||||||
"@opencode/plugin": "2.0.2",
|
"@opencode/plugin": "2.0.4",
|
||||||
"@opencode/schema": "2.0.2",
|
"@opencode/schema": "2.0.4",
|
||||||
"@opentui/core": "0.5.10",
|
"@opentui/core": "0.5.11",
|
||||||
"@opentui/solid": "0.5.10",
|
"@opentui/solid": "0.5.11",
|
||||||
"@oxlint/plugins": "1.82.0",
|
"@oxlint/plugins": "1.83.0",
|
||||||
"@types/bun": "1.3.14",
|
"@types/bun": "1.4.2",
|
||||||
"oxfmt": "0.67.0",
|
"oxfmt": "0.68.0",
|
||||||
"oxlint": "1.82.0",
|
"oxlint": "1.83.0",
|
||||||
"solid-js": "1.9.15",
|
"solid-js": "1.9.15",
|
||||||
"typescript": "7.0.2"
|
"typescript": "7.0.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@opencode/plugin": "2.0.2",
|
"@opencode/plugin": "2.0.4",
|
||||||
"@opentui/core": ">=0.5.10",
|
"@opentui/core": ">=0.5.11",
|
||||||
"@opentui/solid": ">=0.5.10",
|
"@opentui/solid": ">=0.5.11",
|
||||||
"solid-js": ">=1.9.0"
|
"solid-js": ">=1.9.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"zod": "4.1.8"
|
"zod": "4.6.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-10
@@ -59,20 +59,23 @@ export default Plugin.define({
|
|||||||
await quotaRegistration?.events.emit("updated", {});
|
await quotaRegistration?.events.emit("updated", {});
|
||||||
});
|
});
|
||||||
quotaRegistration = await context.rpc.register(QuotaRpc, {
|
quotaRegistration = await context.rpc.register(QuotaRpc, {
|
||||||
status: async ({ sessionID }) => (await quota.status(sessionID)) ?? null,
|
status: async () => quota.status() ?? null,
|
||||||
});
|
});
|
||||||
await quota.init();
|
await quota.init();
|
||||||
// Subscribe before the first read: configuration can publish its catalog while
|
// Subscribe before the first read: configuration can publish its models while
|
||||||
// asynchronous setup is running.
|
// asynchronous setup is running.
|
||||||
const updates = (async () => {
|
const updates = (async () => {
|
||||||
for await (const event of context.event.subscribe({ signal: controller.signal })) {
|
for await (const event of context.event.subscribe({ signal: controller.signal })) {
|
||||||
if (
|
if (event.location) {
|
||||||
event.location &&
|
const workspaceID =
|
||||||
(event.location.directory !== context.location.directory ||
|
"workspaceID" in event.location ? event.location.workspaceID : undefined;
|
||||||
event.location.workspaceID !== context.location.workspaceID)
|
if (
|
||||||
)
|
event.location.directory !== context.location.directory ||
|
||||||
continue;
|
workspaceID !== context.location.workspaceID
|
||||||
if (event.type === "catalog.updated") {
|
)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (event.type === "model.updated") {
|
||||||
models = await discover(context, selected.provider);
|
models = await discover(context, selected.provider);
|
||||||
await context.agent.reload();
|
await context.agent.reload();
|
||||||
} else if (event.type === "agent.updated") {
|
} else if (event.type === "agent.updated") {
|
||||||
@@ -105,7 +108,7 @@ export default Plugin.define({
|
|||||||
}
|
}
|
||||||
})().catch((error) => {
|
})().catch((error) => {
|
||||||
if (!controller.signal.aborted)
|
if (!controller.signal.aborted)
|
||||||
console.error("stanp-opencode catalog update failed", error);
|
console.error("stanp-opencode model update failed", error);
|
||||||
});
|
});
|
||||||
models = await discover(context, selected.provider);
|
models = await discover(context, selected.provider);
|
||||||
const { data: initialAgents } = await context.agent.list();
|
const { data: initialAgents } = await context.agent.list();
|
||||||
|
|||||||
+2
-2
@@ -21,8 +21,8 @@ function priority(model: ModelInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function discover(context: Plugin.Context, providerID: string) {
|
export async function discover(context: Plugin.Context, providerID: string) {
|
||||||
// Native lists already apply activation, integrations, configuration, and catalog transforms.
|
// Native lists already apply activation, integrations, configuration, and model transforms.
|
||||||
const { data } = await context.catalog.model.list();
|
const { data } = await context.model.list();
|
||||||
const models = new Map<string, { model: ModelInfo; serviceTier: string | undefined }>();
|
const models = new Map<string, { model: ModelInfo; serviceTier: string | undefined }>();
|
||||||
for (const model of data) {
|
for (const model of data) {
|
||||||
if (model.providerID === providerID && model.enabled)
|
if (model.providerID === providerID && model.enabled)
|
||||||
|
|||||||
+1
-2
@@ -8,14 +8,13 @@ const window = z.object({
|
|||||||
used: z.number(),
|
used: z.number(),
|
||||||
resetsAt: z.number(),
|
resetsAt: z.number(),
|
||||||
remaining: z.number(),
|
remaining: z.number(),
|
||||||
sessionConsumed: z.number(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const QuotaRpc = Rpc.define({
|
export const QuotaRpc = Rpc.define({
|
||||||
id: "stanp-opencode.quota",
|
id: "stanp-opencode.quota",
|
||||||
methods: {
|
methods: {
|
||||||
status: {
|
status: {
|
||||||
input: z.object({ sessionID: z.string() }),
|
input: z.object({}),
|
||||||
output: z
|
output: z
|
||||||
.object({ plan: z.string(), fetchedAt: z.number(), windows: z.array(window) })
|
.object({ plan: z.string(), fetchedAt: z.number(), windows: z.array(window) })
|
||||||
.nullable(),
|
.nullable(),
|
||||||
|
|||||||
+30
-108
@@ -54,7 +54,7 @@ export interface QuotaSnapshot {
|
|||||||
export interface QuotaStatus {
|
export interface QuotaStatus {
|
||||||
plan: string;
|
plan: string;
|
||||||
fetchedAt: number;
|
fetchedAt: number;
|
||||||
windows: Array<QuotaWindow & { remaining: number; sessionConsumed: number }>;
|
windows: Array<QuotaWindow & { remaining: number }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const storedState = z.object({
|
const storedState = z.object({
|
||||||
@@ -74,14 +74,8 @@ const storedState = z.object({
|
|||||||
),
|
),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
sessions: z.record(
|
|
||||||
z.string(),
|
|
||||||
z.record(
|
|
||||||
z.string(),
|
|
||||||
z.object({ resetsAt: z.number(), lastUsed: z.number(), consumed: z.number() }),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
const legacyStoredState = storedState.extend({ sessions: z.unknown() });
|
||||||
type StoredState = z.infer<typeof storedState>;
|
type StoredState = z.infer<typeof storedState>;
|
||||||
|
|
||||||
function withoutExcludedState(state: StoredState): StoredState {
|
function withoutExcludedState(state: StoredState): StoredState {
|
||||||
@@ -89,20 +83,10 @@ function withoutExcludedState(state: StoredState): StoredState {
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
latest: state.latest && windows?.length ? { ...state.latest, windows } : undefined,
|
latest: state.latest && windows?.length ? { ...state.latest, windows } : undefined,
|
||||||
sessions: Object.fromEntries(
|
|
||||||
Object.entries(state.sessions).map(([session, tracked]) => [
|
|
||||||
session,
|
|
||||||
Object.fromEntries(
|
|
||||||
Object.entries(tracked).filter(
|
|
||||||
([id]) => !isExcludedLimit(id.split(":", 1)[0], undefined),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
type QuotaContext = Pick<Plugin.Context, "integration" | "session" | "storage">;
|
type QuotaContext = Pick<Plugin.Context, "integration" | "storage">;
|
||||||
type QuotaFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
type QuotaFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
||||||
|
|
||||||
const quotaWindow = z.object({
|
const quotaWindow = z.object({
|
||||||
@@ -239,7 +223,8 @@ export class QuotaTracker {
|
|||||||
private timer: ReturnType<typeof setInterval> | undefined;
|
private timer: ReturnType<typeof setInterval> | undefined;
|
||||||
private request: Promise<QuotaSnapshot | undefined> | undefined;
|
private request: Promise<QuotaSnapshot | undefined> | undefined;
|
||||||
private readonly requests = new Set<Promise<QuotaSnapshot | undefined>>();
|
private readonly requests = new Set<Promise<QuotaSnapshot | undefined>>();
|
||||||
private readonly active = new Map<string, Set<string>>();
|
private readonly migrations = new Set<Promise<void>>();
|
||||||
|
private readonly active = new Set<string>();
|
||||||
private controller: AbortController | undefined;
|
private controller: AbortController | undefined;
|
||||||
private generation = 0;
|
private generation = 0;
|
||||||
private disposed = false;
|
private disposed = false;
|
||||||
@@ -276,14 +261,22 @@ export class QuotaTracker {
|
|||||||
: (this.state?.account ?? (await fingerprint(`credential:${credential.refresh}`)));
|
: (this.state?.account ?? (await fingerprint(`credential:${credential.refresh}`)));
|
||||||
if (generation !== this.generation) return;
|
if (generation !== this.generation) return;
|
||||||
if (this.state?.account !== account) {
|
if (this.state?.account !== account) {
|
||||||
const parsed = storedState.safeParse(await this.context.storage.get(STORAGE_KEY));
|
const value = await this.context.storage.get(STORAGE_KEY);
|
||||||
|
const parsed = storedState.safeParse(value);
|
||||||
if (generation !== this.generation) return;
|
if (generation !== this.generation) return;
|
||||||
const stored = parsed.success ? parsed.data : undefined;
|
const stored = parsed.success ? parsed.data : undefined;
|
||||||
if (generation !== this.generation) return;
|
if (generation !== this.generation) return;
|
||||||
this.state =
|
this.state = stored?.account === account ? withoutExcludedState(stored) : { account };
|
||||||
stored?.account === account
|
const legacy = legacyStoredState.safeParse(value);
|
||||||
? withoutExcludedState(stored)
|
if (stored?.account === account && legacy.success) {
|
||||||
: { account, sessions: {} };
|
const migration = this.persist();
|
||||||
|
this.migrations.add(migration);
|
||||||
|
try {
|
||||||
|
await migration;
|
||||||
|
} finally {
|
||||||
|
this.migrations.delete(migration);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (generation !== this.generation) return;
|
if (generation !== this.generation) return;
|
||||||
if (!this.timer) this.timer = setInterval(() => void this.refresh(), this.pollMs);
|
if (!this.timer) this.timer = setInterval(() => void this.refresh(), this.pollMs);
|
||||||
@@ -345,7 +338,7 @@ export class QuotaTracker {
|
|||||||
if (parsed.success && parsed.data.account_id) {
|
if (parsed.success && parsed.data.account_id) {
|
||||||
const account = await fingerprint(`account:${parsed.data.account_id}`);
|
const account = await fingerprint(`account:${parsed.data.account_id}`);
|
||||||
if (generation !== this.generation || !this.state) return;
|
if (generation !== this.generation || !this.state) return;
|
||||||
if (account !== this.state.account) this.state = { account, sessions: {} };
|
if (account !== this.state.account) this.state = { account };
|
||||||
}
|
}
|
||||||
const snapshot = normalizeQuota(payload);
|
const snapshot = normalizeQuota(payload);
|
||||||
if (!snapshot) return;
|
if (!snapshot) return;
|
||||||
@@ -360,102 +353,30 @@ export class QuotaTracker {
|
|||||||
|
|
||||||
private apply(snapshot: QuotaSnapshot) {
|
private apply(snapshot: QuotaSnapshot) {
|
||||||
if (!this.state) return;
|
if (!this.state) return;
|
||||||
for (const root of this.active.keys()) {
|
|
||||||
const tracked = (this.state.sessions[root] ??= {});
|
|
||||||
for (const window of snapshot.windows) {
|
|
||||||
const previous = tracked[window.id];
|
|
||||||
if (!previous) {
|
|
||||||
tracked[window.id] = {
|
|
||||||
resetsAt: window.resetsAt,
|
|
||||||
lastUsed: window.used,
|
|
||||||
consumed: 0,
|
|
||||||
};
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (previous.resetsAt !== window.resetsAt) {
|
|
||||||
previous.resetsAt = window.resetsAt;
|
|
||||||
previous.lastUsed = window.used;
|
|
||||||
previous.consumed += window.used;
|
|
||||||
} else if (window.used >= previous.lastUsed) {
|
|
||||||
previous.consumed += window.used - previous.lastUsed;
|
|
||||||
previous.lastUsed = window.used;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.state.latest = snapshot;
|
this.state.latest = snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async root(sessionID: string) {
|
|
||||||
let current = sessionID;
|
|
||||||
const seen = new Set<string>();
|
|
||||||
while (!seen.has(current)) {
|
|
||||||
seen.add(current);
|
|
||||||
const session = await this.context.session.get({ sessionID: current });
|
|
||||||
if (!session.parentID) return current;
|
|
||||||
current = session.parentID;
|
|
||||||
}
|
|
||||||
return sessionID;
|
|
||||||
}
|
|
||||||
|
|
||||||
async start(sessionID: string) {
|
async start(sessionID: string) {
|
||||||
|
if (this.active.has(sessionID)) return;
|
||||||
const generation = this.generation;
|
const generation = this.generation;
|
||||||
try {
|
const snapshot = await this.refresh();
|
||||||
const root = await this.root(sessionID);
|
if (!snapshot || generation !== this.generation) return;
|
||||||
if (generation !== this.generation) return;
|
this.active.add(sessionID);
|
||||||
const family = this.active.get(root);
|
|
||||||
if (family?.has(sessionID)) return;
|
|
||||||
const snapshot = await this.refresh();
|
|
||||||
if (!snapshot || !this.state || generation !== this.generation) return;
|
|
||||||
if (!family) {
|
|
||||||
const previous = this.state.sessions[root] ?? {};
|
|
||||||
this.state.sessions[root] = Object.fromEntries(
|
|
||||||
snapshot.windows.map((window) => [
|
|
||||||
window.id,
|
|
||||||
{
|
|
||||||
resetsAt: window.resetsAt,
|
|
||||||
lastUsed: window.used,
|
|
||||||
consumed: previous[window.id]?.consumed ?? 0,
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await this.persist();
|
|
||||||
if (generation !== this.generation) return;
|
|
||||||
await this.changed();
|
|
||||||
if (generation !== this.generation) return;
|
|
||||||
const active = family ?? new Set<string>();
|
|
||||||
active.add(sessionID);
|
|
||||||
this.active.set(root, active);
|
|
||||||
} catch {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async complete(sessionID: string) {
|
async complete(sessionID: string) {
|
||||||
try {
|
if (!this.active.delete(sessionID)) return;
|
||||||
const root = await this.root(sessionID);
|
await this.refresh();
|
||||||
const family = this.active.get(root);
|
|
||||||
if (!family?.has(sessionID)) return;
|
|
||||||
await this.refresh();
|
|
||||||
family.delete(sessionID);
|
|
||||||
if (family.size === 0) this.active.delete(root);
|
|
||||||
await this.persist();
|
|
||||||
await this.changed();
|
|
||||||
} catch {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async status(sessionID: string): Promise<QuotaStatus | undefined> {
|
status(): QuotaStatus | undefined {
|
||||||
if (!this.state?.latest) return;
|
if (!this.state?.latest) return;
|
||||||
const tracked = this.state.sessions[await this.root(sessionID)];
|
|
||||||
return {
|
return {
|
||||||
plan: this.state.latest.plan,
|
plan: this.state.latest.plan,
|
||||||
fetchedAt: this.state.latest.fetchedAt,
|
fetchedAt: this.state.latest.fetchedAt,
|
||||||
windows: this.state.latest.windows.map((window) => ({
|
windows: this.state.latest.windows.map((window) => ({
|
||||||
...window,
|
...window,
|
||||||
remaining: Math.max(0, 100 - window.used),
|
remaining: Math.max(0, 100 - window.used),
|
||||||
sessionConsumed: tracked?.[window.id]?.consumed ?? 0,
|
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -465,10 +386,9 @@ export class QuotaTracker {
|
|||||||
const value: Schema.Json = this.state.latest
|
const value: Schema.Json = this.state.latest
|
||||||
? {
|
? {
|
||||||
account: this.state.account,
|
account: this.state.account,
|
||||||
sessions: this.state.sessions,
|
|
||||||
latest: this.state.latest,
|
latest: this.state.latest,
|
||||||
}
|
}
|
||||||
: { account: this.state.account, sessions: this.state.sessions };
|
: { account: this.state.account };
|
||||||
await this.context.storage.set(STORAGE_KEY, value);
|
await this.context.storage.set(STORAGE_KEY, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,6 +398,8 @@ export class QuotaTracker {
|
|||||||
this.controller?.abort();
|
this.controller?.abort();
|
||||||
this.controller = undefined;
|
this.controller = undefined;
|
||||||
this.request = undefined;
|
this.request = undefined;
|
||||||
|
this.active.clear();
|
||||||
|
await Promise.all(this.migrations);
|
||||||
if (this.state) await this.clear();
|
if (this.state) await this.clear();
|
||||||
}
|
}
|
||||||
await this.refresh();
|
await this.refresh();
|
||||||
@@ -489,6 +411,6 @@ export class QuotaTracker {
|
|||||||
this.controller?.abort();
|
this.controller?.abort();
|
||||||
if (this.timer) clearInterval(this.timer);
|
if (this.timer) clearInterval(this.timer);
|
||||||
this.timer = undefined;
|
this.timer = undefined;
|
||||||
await Promise.all(this.requests);
|
await Promise.all([...this.requests, ...this.migrations]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-6
@@ -33,14 +33,11 @@ function resetTiming(resetsAt: number, now: number) {
|
|||||||
return `${minutes}m`;
|
return `${minutes}m`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatQuotaWindow(
|
export function formatQuotaWindow(window: QuotaWindow & { remaining: number }, now = Date.now()) {
|
||||||
window: QuotaWindow & { remaining: number; sessionConsumed: number },
|
|
||||||
now = Date.now(),
|
|
||||||
) {
|
|
||||||
const label = window.label
|
const label = window.label
|
||||||
? `${window.label} ${duration(window.seconds)}`
|
? `${window.label} ${duration(window.seconds)}`
|
||||||
: duration(window.seconds);
|
: duration(window.seconds);
|
||||||
return `${label}: ${percent(window.remaining)}% · ~${percent(window.sessionConsumed)}pp · ${resetTiming(window.resetsAt, now)}`;
|
return `${label}: ${percent(window.remaining)}% · ${resetTiming(window.resetsAt, now)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadQuotaStatus(load: () => Promise<QuotaStatus | null>) {
|
export async function loadQuotaStatus(load: () => Promise<QuotaStatus | null>) {
|
||||||
@@ -66,7 +63,7 @@ export default Plugin.define({
|
|||||||
const Slot = (props: { sessionID: string }) => {
|
const Slot = (props: { sessionID: string }) => {
|
||||||
const [status] = createResource(
|
const [status] = createResource(
|
||||||
() => `${props.sessionID}:${revision()}`,
|
() => `${props.sessionID}:${revision()}`,
|
||||||
() => loadQuotaStatus(() => quota.status({ sessionID: props.sessionID })),
|
() => loadQuotaStatus(() => quota.status({})),
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<Show when={status()}>
|
<Show when={status()}>
|
||||||
|
|||||||
+38
-8
@@ -52,6 +52,7 @@ async function host(
|
|||||||
> = {},
|
> = {},
|
||||||
configuredMcpTools: string[] = [],
|
configuredMcpTools: string[] = [],
|
||||||
directory = "/test",
|
directory = "/test",
|
||||||
|
workspaceID?: string,
|
||||||
) {
|
) {
|
||||||
const agents = new Map<string, DeepMutable<Agent.Info>>();
|
const agents = new Map<string, DeepMutable<Agent.Info>>();
|
||||||
const build: DeepMutable<Agent.Info> = Agent.Info.default(Agent.ID.make("build"));
|
const build: DeepMutable<Agent.Info> = Agent.Info.default(Agent.ID.make("build"));
|
||||||
@@ -131,13 +132,11 @@ async function host(
|
|||||||
// SAFETY: This test host implements the native APIs used by setup; unrelated context
|
// SAFETY: This test host implements the native APIs used by setup; unrelated context
|
||||||
// services are deliberately absent so unexpected new dependencies fail the test.
|
// services are deliberately absent so unexpected new dependencies fail the test.
|
||||||
const context = {
|
const context = {
|
||||||
location: { directory },
|
location: { directory, workspaceID },
|
||||||
options,
|
options,
|
||||||
catalog: {
|
model: {
|
||||||
model: {
|
async list() {
|
||||||
async list() {
|
return { data: models };
|
||||||
return { data: models };
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
event: {
|
event: {
|
||||||
@@ -249,7 +248,16 @@ async function host(
|
|||||||
async refresh(next: ModelInfo[]) {
|
async refresh(next: ModelInfo[]) {
|
||||||
models = next;
|
models = next;
|
||||||
reloaded = Promise.withResolvers<void>();
|
reloaded = Promise.withResolvers<void>();
|
||||||
events.enqueue({ type: "catalog.updated" });
|
events.enqueue({ type: "model.updated" });
|
||||||
|
await reloaded.promise;
|
||||||
|
},
|
||||||
|
publishModels(next: ModelInfo[], location?: { directory: string; workspaceID?: string }) {
|
||||||
|
models = next;
|
||||||
|
if (location) events.enqueue({ type: "model.updated", location });
|
||||||
|
else events.enqueue({ type: "model.updated" });
|
||||||
|
},
|
||||||
|
async waitForReload() {
|
||||||
|
reloaded = Promise.withResolvers<void>();
|
||||||
await reloaded.promise;
|
await reloaded.promise;
|
||||||
},
|
},
|
||||||
async changeBuildPermissions(permissions: Agent.Info["permissions"]) {
|
async changeBuildPermissions(permissions: Agent.Info["permissions"]) {
|
||||||
@@ -668,7 +676,12 @@ test("coordinator defaults expose their effort variant without relying on it for
|
|||||||
expect(custom.agents.get("coordinate")?.request.settings.reasoningEffort).toBe("xhigh");
|
expect(custom.agents.get("coordinate")?.request.settings.reasoningEffort).toBe("xhigh");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("catalog updates activate late models and remove unavailable agents", async () => {
|
test("the current host model API filters discovery and reloads changed availability", async () => {
|
||||||
|
const disabled = { ...reasoningModel("gpt-5.6-luna"), enabled: false };
|
||||||
|
const other = { ...reasoningModel("gpt-5.6-sol"), providerID: Provider.ID.make("other") };
|
||||||
|
expect((await host([disabled, other, ...allModels.slice(1)])).agents.has("coordinate")).toBe(
|
||||||
|
false,
|
||||||
|
);
|
||||||
const result = await host([]);
|
const result = await host([]);
|
||||||
await result.refresh(allModels);
|
await result.refresh(allModels);
|
||||||
expect(String(result.agents.get("coordinate")?.model?.id)).toBe("gpt-6-astra");
|
expect(String(result.agents.get("coordinate")?.model?.id)).toBe("gpt-6-astra");
|
||||||
@@ -718,6 +731,23 @@ test("events from another location do not reload this location's agents", async
|
|||||||
).toBe("ask");
|
).toBe("ask");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("model updates require an exact workspace match within the same directory", async () => {
|
||||||
|
const result = await host([], { provider: "test" }, {}, [], "/test", "workspace-a");
|
||||||
|
|
||||||
|
result.publishModels(allModels, { directory: "/test" });
|
||||||
|
await Bun.sleep(0);
|
||||||
|
expect(result.agents.has("coordinate")).toBe(false);
|
||||||
|
|
||||||
|
result.publishModels(allModels, { directory: "/test", workspaceID: "workspace-b" });
|
||||||
|
await Bun.sleep(0);
|
||||||
|
expect(result.agents.has("coordinate")).toBe(false);
|
||||||
|
|
||||||
|
const reloaded = result.waitForReload();
|
||||||
|
result.publishModels(allModels, { directory: "/test", workspaceID: "workspace-a" });
|
||||||
|
await reloaded;
|
||||||
|
expect(result.agents.has("coordinate")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
test("todo lists persist within one session without leaking to another", async () => {
|
test("todo lists persist within one session without leaking to another", async () => {
|
||||||
const result = await host();
|
const result = await host();
|
||||||
const todos = [{ id: "1", content: "Implement", status: "in_progress", priority: "high" }];
|
const todos = [{ id: "1", content: "Implement", status: "in_progress", priority: "high" }];
|
||||||
|
|||||||
+31
-47
@@ -173,10 +173,6 @@ function fixture(
|
|||||||
storageReads: Promise<Schema.Json | undefined>[] = [],
|
storageReads: Promise<Schema.Json | undefined>[] = [],
|
||||||
) {
|
) {
|
||||||
const stored = new Map<string, Schema.Json>();
|
const stored = new Map<string, Schema.Json>();
|
||||||
const sessions = new Map([
|
|
||||||
["root", {}],
|
|
||||||
["child", { parentID: "root" }],
|
|
||||||
]);
|
|
||||||
let calls = 0;
|
let calls = 0;
|
||||||
let storageCalls = 0;
|
let storageCalls = 0;
|
||||||
let changes = 0;
|
let changes = 0;
|
||||||
@@ -198,12 +194,6 @@ function fixture(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as never,
|
} as never,
|
||||||
session: {
|
|
||||||
async get({ sessionID }: { sessionID: string }) {
|
|
||||||
// SAFETY: QuotaTracker reads only parentID from this focused fixture.
|
|
||||||
return sessions.get(sessionID) as never;
|
|
||||||
},
|
|
||||||
} as never,
|
|
||||||
storage: {
|
storage: {
|
||||||
async get(key: string) {
|
async get(key: string) {
|
||||||
storageCalls++;
|
storageCalls++;
|
||||||
@@ -242,6 +232,7 @@ function fixture(
|
|||||||
storageCalls: () => storageCalls,
|
storageCalls: () => storageCalls,
|
||||||
changes: () => changes,
|
changes: () => changes,
|
||||||
headers,
|
headers,
|
||||||
|
stored,
|
||||||
switch(credential: typeof current) {
|
switch(credential: typeof current) {
|
||||||
current = credential;
|
current = credential;
|
||||||
},
|
},
|
||||||
@@ -256,7 +247,7 @@ async function accountFingerprint(id: string) {
|
|||||||
return Buffer.from(bytes).toString("hex");
|
return Buffer.from(bytes).toString("hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
test("removes cached Spark and representative reserve windows and consumption while offline", async () => {
|
test("reads old cached snapshots without session estimates and removes excluded windows", async () => {
|
||||||
const cached = {
|
const cached = {
|
||||||
account: await accountFingerprint("account-one"),
|
account: await accountFingerprint("account-one"),
|
||||||
latest: {
|
latest: {
|
||||||
@@ -331,22 +322,23 @@ test("removes cached Spark and representative reserve windows and consumption wh
|
|||||||
);
|
);
|
||||||
|
|
||||||
await result.tracker.init();
|
await result.tracker.init();
|
||||||
const status = await result.tracker.status("root");
|
const status = result.tracker.status();
|
||||||
expect(status?.windows.map((window) => window.id)).toEqual([
|
expect(status?.windows.map((window) => window.id)).toEqual([
|
||||||
"codex:primary",
|
"codex:primary",
|
||||||
"codex_luna:primary",
|
"codex_luna:primary",
|
||||||
]);
|
]);
|
||||||
expect(status?.windows[0]?.sessionConsumed).toBe(2);
|
expect(status?.windows[0]).not.toHaveProperty("sessionConsumed");
|
||||||
expect(status?.windows[1]?.sessionConsumed).toBe(3);
|
expect(result.stored.get("chatgpt-quota")).not.toHaveProperty("sessions");
|
||||||
|
expect(result.calls()).toBe(0);
|
||||||
await result.tracker.dispose();
|
await result.tracker.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("activates only for OAuth and establishes an awaited root baseline shared by children", async () => {
|
test("activates only for OAuth and refreshes quota at request start", async () => {
|
||||||
const key = fixture({ type: "key", key: "secret" }, [plus]);
|
const key = fixture({ type: "key", key: "secret" }, [plus]);
|
||||||
await key.tracker.init();
|
await key.tracker.init();
|
||||||
await key.tracker.start("root");
|
await key.tracker.start("root");
|
||||||
expect(key.calls()).toBe(0);
|
expect(key.calls()).toBe(0);
|
||||||
expect(await key.tracker.status("root")).toBeUndefined();
|
expect(key.tracker.status()).toBeUndefined();
|
||||||
await key.tracker.dispose();
|
await key.tracker.dispose();
|
||||||
|
|
||||||
const oauth = fixture(
|
const oauth = fixture(
|
||||||
@@ -372,13 +364,14 @@ test("activates only for OAuth and establishes an awaited root baseline shared b
|
|||||||
expect(oauth.calls()).toBe(1);
|
expect(oauth.calls()).toBe(1);
|
||||||
expect(oauth.headers[0]?.get("chatgpt-account-id")).toBe("account-one");
|
expect(oauth.headers[0]?.get("chatgpt-account-id")).toBe("account-one");
|
||||||
await oauth.tracker.refresh();
|
await oauth.tracker.refresh();
|
||||||
const child = await oauth.tracker.status("child");
|
const status = oauth.tracker.status();
|
||||||
expect(child?.windows[0]?.sessionConsumed).toBe(5);
|
expect(status?.windows[0]?.remaining).toBe(82.5);
|
||||||
expect(child?.windows[0]?.remaining).toBe(82.5);
|
expect(status?.windows[0]).not.toHaveProperty("sessionConsumed");
|
||||||
|
expect(oauth.stored.get("chatgpt-quota")).not.toHaveProperty("sessions");
|
||||||
await oauth.tracker.dispose();
|
await oauth.tracker.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("polls, carries consumption across quota resets, tolerates errors, and clears on logout", async () => {
|
test("polls, tolerates errors, and clears on logout", async () => {
|
||||||
const reset = {
|
const reset = {
|
||||||
...plus,
|
...plus,
|
||||||
rate_limit: {
|
rate_limit: {
|
||||||
@@ -403,12 +396,12 @@ test("polls, carries consumption across quota resets, tolerates errors, and clea
|
|||||||
await result.tracker.init();
|
await result.tracker.init();
|
||||||
await result.tracker.start("root");
|
await result.tracker.start("root");
|
||||||
await Bun.sleep(35);
|
await Bun.sleep(35);
|
||||||
const status = await result.tracker.status("root");
|
const status = result.tracker.status();
|
||||||
expect(result.calls()).toBeGreaterThanOrEqual(3);
|
expect(result.calls()).toBeGreaterThanOrEqual(3);
|
||||||
expect(status?.windows[0]?.sessionConsumed).toBe(2);
|
expect(status?.windows[0]?.remaining).toBe(98);
|
||||||
result.logout();
|
result.logout();
|
||||||
await result.tracker.authChanged(true);
|
await result.tracker.authChanged(true);
|
||||||
expect(await result.tracker.status("root")).toBeUndefined();
|
expect(result.tracker.status()).toBeUndefined();
|
||||||
const calls = result.calls();
|
const calls = result.calls();
|
||||||
await result.tracker.dispose();
|
await result.tracker.dispose();
|
||||||
await Bun.sleep(20);
|
await Bun.sleep(20);
|
||||||
@@ -424,12 +417,11 @@ test("sidebar text places reset timing beside latest remaining quota", () => {
|
|||||||
label: null,
|
label: null,
|
||||||
used: 25,
|
used: 25,
|
||||||
remaining: 75,
|
remaining: 75,
|
||||||
sessionConsumed: 1.5,
|
|
||||||
resetsAt: 100_000 + 2 * 86_400_000 + 5 * 3_600_000,
|
resetsAt: 100_000 + 2 * 86_400_000 + 5 * 3_600_000,
|
||||||
},
|
},
|
||||||
100_000,
|
100_000,
|
||||||
),
|
),
|
||||||
).toBe("7d: 75% · ~1.5pp · 2d 5h");
|
).toBe("7d: 75% · 2d 5h");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("sidebar reset timing uses compact future units and handles boundaries", () => {
|
test("sidebar reset timing uses compact future units and handles boundaries", () => {
|
||||||
@@ -442,17 +434,16 @@ test("sidebar reset timing uses compact future units and handles boundaries", ()
|
|||||||
label: null,
|
label: null,
|
||||||
used: 25,
|
used: 25,
|
||||||
remaining: 75,
|
remaining: 75,
|
||||||
sessionConsumed: 1.5,
|
|
||||||
resetsAt: now + resetIn,
|
resetsAt: now + resetIn,
|
||||||
},
|
},
|
||||||
now,
|
now,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(format(2 * 3_600_000 + 15 * 60_000)).toBe("5h: 75% · ~1.5pp · 2h 15m");
|
expect(format(2 * 3_600_000 + 15 * 60_000)).toBe("5h: 75% · 2h 15m");
|
||||||
expect(format(3_600_000)).toBe("5h: 75% · ~1.5pp · 1h");
|
expect(format(3_600_000)).toBe("5h: 75% · 1h");
|
||||||
expect(format(15 * 60_000)).toBe("5h: 75% · ~1.5pp · 15m");
|
expect(format(15 * 60_000)).toBe("5h: 75% · 15m");
|
||||||
expect(format(60_000)).toBe("5h: 75% · ~1.5pp · 1m");
|
expect(format(60_000)).toBe("5h: 75% · 1m");
|
||||||
expect(format(59_999)).toBe("5h: 75% · ~1.5pp · <1m");
|
expect(format(59_999)).toBe("5h: 75% · <1m");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("sidebar reset timing preserves labels and distinguishes stale and unavailable timestamps", () => {
|
test("sidebar reset timing preserves labels and distinguishes stale and unavailable timestamps", () => {
|
||||||
@@ -462,17 +453,16 @@ test("sidebar reset timing preserves labels and distinguishes stale and unavaila
|
|||||||
label: "GPT-5.6 Luna",
|
label: "GPT-5.6 Luna",
|
||||||
used: 99.95,
|
used: 99.95,
|
||||||
remaining: 0.05,
|
remaining: 0.05,
|
||||||
sessionConsumed: 1.5,
|
|
||||||
};
|
};
|
||||||
expect(formatQuotaWindow({ ...window, resetsAt: 999 }, 1_000)).toBe(
|
expect(formatQuotaWindow({ ...window, resetsAt: 999 }, 1_000)).toBe(
|
||||||
"GPT-5.6 Luna 5h: <0.1% · ~1.5pp · due",
|
"GPT-5.6 Luna 5h: <0.1% · due",
|
||||||
);
|
);
|
||||||
expect(formatQuotaWindow({ ...window, resetsAt: Number.NaN }, 1_000)).toBe(
|
expect(formatQuotaWindow({ ...window, resetsAt: Number.NaN }, 1_000)).toBe(
|
||||||
"GPT-5.6 Luna 5h: <0.1% · ~1.5pp · unavailable",
|
"GPT-5.6 Luna 5h: <0.1% · unavailable",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("inactive roots freeze, resume from a cached baseline on failure, and deactivate by family", async () => {
|
test("request completion refreshes once across terminal and idle events", async () => {
|
||||||
const used = (percent: number) => ({
|
const used = (percent: number) => ({
|
||||||
...plus,
|
...plus,
|
||||||
rate_limit: {
|
rate_limit: {
|
||||||
@@ -492,16 +482,10 @@ test("inactive roots freeze, resume from a cached baseline on failure, and deact
|
|||||||
await result.tracker.init();
|
await result.tracker.init();
|
||||||
await result.tracker.start("root");
|
await result.tracker.start("root");
|
||||||
await result.tracker.complete("root");
|
await result.tracker.complete("root");
|
||||||
expect((await result.tracker.status("root"))?.windows[0]?.sessionConsumed).toBe(1);
|
expect(result.tracker.status()?.windows[0]?.remaining).toBe(89);
|
||||||
await result.tracker.refresh();
|
|
||||||
expect((await result.tracker.status("root"))?.windows[0]?.sessionConsumed).toBe(1);
|
|
||||||
|
|
||||||
await result.tracker.start("root");
|
|
||||||
await result.tracker.start("child");
|
|
||||||
await result.tracker.complete("root");
|
await result.tracker.complete("root");
|
||||||
await result.tracker.refresh();
|
expect(result.calls()).toBe(2);
|
||||||
await result.tracker.complete("child");
|
expect(result.tracker.status()?.windows[0]?.remaining).toBe(89);
|
||||||
expect((await result.tracker.status("root"))?.windows[0]?.sessionConsumed).toBe(6);
|
|
||||||
await result.tracker.dispose();
|
await result.tracker.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -542,10 +526,10 @@ test("an auth switch detaches an in-flight old-account response and immediately
|
|||||||
expect(result.calls()).toBe(2);
|
expect(result.calls()).toBe(2);
|
||||||
pending.resolve(plus);
|
pending.resolve(plus);
|
||||||
await old;
|
await old;
|
||||||
expect((await result.tracker.status("root"))?.windows[0]?.used).toBe(70);
|
expect(result.tracker.status()?.windows[0]?.used).toBe(70);
|
||||||
expect(result.headers[1]?.get("chatgpt-account-id")).toBe("account-two");
|
expect(result.headers[1]?.get("chatgpt-account-id")).toBe("account-two");
|
||||||
await result.tracker.refresh();
|
await result.tracker.refresh();
|
||||||
expect((await result.tracker.status("root"))?.windows[0]?.sessionConsumed).toBe(0);
|
expect(result.tracker.status()?.windows[0]).not.toHaveProperty("sessionConsumed");
|
||||||
await result.tracker.dispose();
|
await result.tracker.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -577,7 +561,7 @@ test("an auth switch during an old account storage read cannot restore stale sta
|
|||||||
expect(result.calls()).toBe(1);
|
expect(result.calls()).toBe(1);
|
||||||
pending.resolve(undefined);
|
pending.resolve(undefined);
|
||||||
await old;
|
await old;
|
||||||
expect((await result.tracker.status("root"))?.windows[0]?.used).toBe(64);
|
expect(result.tracker.status()?.windows[0]?.used).toBe(64);
|
||||||
expect(result.headers[0]?.get("chatgpt-account-id")).toBe("account-two");
|
expect(result.headers[0]?.get("chatgpt-account-id")).toBe("account-two");
|
||||||
await result.tracker.dispose();
|
await result.tracker.dispose();
|
||||||
});
|
});
|
||||||
|
|||||||
+7
-7
@@ -18,7 +18,6 @@ const status = (plan: string, remaining: number): QuotaStatus => ({
|
|||||||
used: 100 - remaining,
|
used: 100 - remaining,
|
||||||
resetsAt: 2,
|
resetsAt: 2,
|
||||||
remaining,
|
remaining,
|
||||||
sessionConsumed: 1.5,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@@ -32,13 +31,13 @@ test("built quota slot stays reactive across pending, empty, failure, update, an
|
|||||||
const { default: plugin } = tui;
|
const { default: plugin } = tui;
|
||||||
const pending = Promise.withResolvers<QuotaStatus | null>();
|
const pending = Promise.withResolvers<QuotaStatus | null>();
|
||||||
const responses: Array<() => Promise<QuotaStatus | null>> = [() => pending.promise];
|
const responses: Array<() => Promise<QuotaStatus | null>> = [() => pending.promise];
|
||||||
const sessions: string[] = [];
|
let statusCalls = 0;
|
||||||
let slotRender: SlotRender | undefined;
|
let slotRender: SlotRender | undefined;
|
||||||
let notifyUpdated: (() => void) | undefined;
|
let notifyUpdated: (() => void) | undefined;
|
||||||
|
|
||||||
const quota = {
|
const quota = {
|
||||||
status(input: { sessionID: string }) {
|
status() {
|
||||||
sessions.push(input.sessionID);
|
statusCalls++;
|
||||||
const response = responses.shift();
|
const response = responses.shift();
|
||||||
if (!response) throw new Error("Missing test response");
|
if (!response) throw new Error("Missing test response");
|
||||||
return response();
|
return response();
|
||||||
@@ -84,7 +83,8 @@ test("built quota slot stays reactive across pending, empty, failure, update, an
|
|||||||
|
|
||||||
pending.resolve(status("plus", 75));
|
pending.resolve(status("plus", 75));
|
||||||
await setup.waitForFrame((frame) => frame.includes("ChatGPT quota (plus)"));
|
await setup.waitForFrame((frame) => frame.includes("ChatGPT quota (plus)"));
|
||||||
expect(setup.captureCharFrame()).toContain("5h: 75% · ~1.5pp · due");
|
expect(setup.captureCharFrame()).toContain("5h: 75% · due");
|
||||||
|
expect(setup.captureCharFrame()).not.toContain("~");
|
||||||
|
|
||||||
responses.push(async () => null);
|
responses.push(async () => null);
|
||||||
notifyUpdated();
|
notifyUpdated();
|
||||||
@@ -94,13 +94,13 @@ test("built quota slot stays reactive across pending, empty, failure, update, an
|
|||||||
throw new Error("disconnected");
|
throw new Error("disconnected");
|
||||||
});
|
});
|
||||||
notifyUpdated();
|
notifyUpdated();
|
||||||
await setup.waitFor(() => sessions.length === 3);
|
await setup.waitFor(() => statusCalls === 3);
|
||||||
expect(setup.captureCharFrame()).not.toContain("ChatGPT quota");
|
expect(setup.captureCharFrame()).not.toContain("ChatGPT quota");
|
||||||
|
|
||||||
responses.push(async () => status("pro", 42));
|
responses.push(async () => status("pro", 42));
|
||||||
setSessionID("session-two");
|
setSessionID("session-two");
|
||||||
await setup.waitForFrame((frame) => frame.includes("ChatGPT quota (pro)"));
|
await setup.waitForFrame((frame) => frame.includes("ChatGPT quota (pro)"));
|
||||||
expect(sessions).toEqual(["session-one", "session-one", "session-one", "session-two"]);
|
expect(statusCalls).toBe(4);
|
||||||
} finally {
|
} finally {
|
||||||
setup.renderer.destroy();
|
setup.renderer.destroy();
|
||||||
if (cleanup) await cleanup();
|
if (cleanup) await cleanup();
|
||||||
|
|||||||
Reference in New Issue
Block a user