Compare commits
3
Commits
v1.1.0
..
a6cb0beade
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6cb0beade | ||
|
|
c48fe99b96 | ||
|
|
411cdd13ff |
@@ -4,7 +4,7 @@ OpenCode V2 plugin providing a `coordinate` agent and fast/good/deep worker pair
|
|||||||
|
|
||||||
## Install the latest release
|
## Install the latest release
|
||||||
|
|
||||||
Requires **OpenCode V2** (`opencode2`), **Bun 1.3.14+**, Bash, curl, jq, and `sha256sum` (Linux/WSL). The native plugin API is pinned to `@opencode/plugin@0.0.0-beta-19378`; use the matching OpenCode beta.
|
Requires **OpenCode V2 2.0.2** (`opencode2`), **Bun 1.3.14+**, Bash, curl, jq, and `sha256sum` (Linux/WSL). The native plugin API is pinned to `@opencode/plugin@2.0.2`; use the matching stable OpenCode release.
|
||||||
|
|
||||||
Run the installer without sudo:
|
Run the installer without sudo:
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ curl -fsSL https://git.krtss.de/StanPonomarev/stanp-opencode/raw/branch/main/ins
|
|||||||
|
|
||||||
From a checkout, run `bash install.sh` directly. Rerun the same script to upgrade to the latest published, non-prerelease Gitea release.
|
From a checkout, run `bash install.sh` directly. Rerun the same script to upgrade to the latest published, non-prerelease Gitea release.
|
||||||
|
|
||||||
The installer downloads `stanp-opencode.tgz` and its SHA-256 checksum, verifies and extracts the self-contained archive, then activates the plugin only after importing and checking the native V2 export. Download, extraction, and validation failures leave the previous active plugin untouched. The checksum detects corruption; it is not a signature independent of the release server.
|
The installer downloads `stanp-opencode.tgz` and its SHA-256 checksum, verifies and extracts the self-contained archive, then activates the plugin only after importing and checking both the native V2 server and TUI exports. Download, extraction, and validation failures leave the previous active plugin untouched. The checksum detects corruption; it is not a signature independent of the release server.
|
||||||
|
|
||||||
Installation defaults to `~/.config/opencode` and respects `XDG_CONFIG_HOME`. Override it explicitly when needed:
|
Installation defaults to `~/.config/opencode` and respects `XDG_CONFIG_HOME`. Override it explicitly when needed:
|
||||||
|
|
||||||
@@ -26,6 +26,24 @@ The installer atomically replaces the package directory at `plugins/stanp-openco
|
|||||||
|
|
||||||
Restart `opencode2` after installation (or `opencode2 service restart` for an existing service). Connect your provider, then select `coordinate` in the agent picker. The default configuration uses OpenAI GPT models; agents are only enabled when the required models are available.
|
Restart `opencode2` after installation (or `opencode2 service restart` for an existing service). Connect your provider, then select `coordinate` in the agent picker. The default configuration uses OpenAI GPT models; agents are only enabled when the required models are available.
|
||||||
|
|
||||||
|
## Install from a local checkout
|
||||||
|
|
||||||
|
To build and install the current checkout instead of downloading a release, install Bash, jq, and **Bun 1.3.14+**, then run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bash /path/to/stanp-opencode/install-local.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The script may be invoked from any working directory. It runs `bun install --frozen-lockfile` (which may access the package registry) and `bun run build` in the checkout containing the script on every run. It validates the native V2 and TUI bundles, copies them into the same installed package layout as the release installer, and preserves existing plugin options, unrelated `opencode.json` settings, and `opencode.jsonc`. Dependency installation, build, validation, and configuration parsing failures leave the currently installed plugin and configuration untouched.
|
||||||
|
|
||||||
|
The configuration directory defaults to `~/.config/opencode`, respects `XDG_CONFIG_HOME`, and can be overridden explicitly:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
OPENCODE_CONFIG_DIR=/path/to/opencode-config bash /path/to/stanp-opencode/install-local.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Restart `opencode2` after installation (or `opencode2 service restart`).
|
||||||
|
|
||||||
## Configure
|
## Configure
|
||||||
|
|
||||||
See [GPT configuration](examples/gpt.opencode.jsonc) and [custom model assignments](examples/custom.opencode.jsonc). When using the installer, point the example's plugin package entry at the installed package directory rather than the unpublished npm package name. Configured local plugin paths must be directories; pointing at `plugins/stanp-opencode.js` causes OpenCode to reject that configured entry and auto-load the file without its options:
|
See [GPT configuration](examples/gpt.opencode.jsonc) and [custom model assignments](examples/custom.opencode.jsonc). When using the installer, point the example's plugin package entry at the installed package directory rather than the unpublished npm package name. Configured local plugin paths must be directories; pointing at `plugins/stanp-opencode.js` causes OpenCode to reject that configured entry and auto-load the file without its options:
|
||||||
@@ -47,10 +65,18 @@ See [GPT configuration](examples/gpt.opencode.jsonc) and [custom model assignmen
|
|||||||
|
|
||||||
This relative path assumes the configuration file is in the selected global config directory. Use an absolute path in project configuration. Remove any old V1 `plugin` entry when migrating; V2 uses `plugins`. `lunaPriority` requests priority service where supported and can increase cost; set it to `false` to use the provider default.
|
This relative path assumes the configuration file is in the selected global config directory. Use an absolute path in project configuration. Remove any old V1 `plugin` entry when migrating; V2 uses `plugins`. `lunaPriority` requests priority service where supported and can increase cost; set it to `false` to use the provider default.
|
||||||
|
|
||||||
The plugin supplies session-local `todoread` and `todowrite` tools when no other plugin provides them. In this pinned V2 beta, custom tools cannot open permission prompts: an `ask` or `deny` rule blocks these todo tools rather than bypassing the rule. Explicitly allow them if you want to use them.
|
The plugin supplies session-local `todoread` and `todowrite` tools when no other plugin provides them. In OpenCode V2 2.0.2, custom tools cannot open permission prompts: an `ask` or `deny` rule blocks these todo tools rather than bypassing the rule. Explicitly allow them if you want to use them.
|
||||||
|
|
||||||
When an MCP server named `codegraph` is already configured, its tools are exposed directly to `coordinate` and retain the built-in `build` agent's matching allow, ask, and deny rules. The plugin does not configure or start a missing server, and no other MCP server is exposed this way.
|
When an MCP server named `codegraph` is already configured, its tools are exposed directly to `coordinate` and retain the built-in `build` agent's matching allow, ask, and deny rules. The plugin does not configure or start a missing server, and no other MCP server is exposed this way.
|
||||||
|
|
||||||
|
## ChatGPT subscription quota
|
||||||
|
|
||||||
|
When OpenCode's active `openai` integration uses ChatGPT OAuth, the plugin reads the same account usage endpoint as Codex. It queries before a session's first model request (including a resumed session and child sessions), about every 60 seconds, and when session execution completes, fails, is interrupted, or becomes idle. API-key connections and other providers make no quota requests and show no quota UI.
|
||||||
|
|
||||||
|
The automatically loaded TUI plugin adds each valid window returned by OpenAI to the sidebar, including named/model-specific limits. Absent or malformed windows are hidden. OpenAI's current Codex contract does not provide a per-window "informational" or "not enforced" flag, so an explicitly returned five-hour window is shown for every plan, including Pro; silently discarding it based only on plan and duration would misrepresent the authoritative response. Each line shows the latest **remaining** account quota and the estimated **percentage points** consumed while the root session family is active. A root session and all of its subagents share one baseline, so child activity is included without counting the same account delta once per child.
|
||||||
|
|
||||||
|
The estimate is based on changes in OpenAI's account-wide percentages, not token accounting. Concurrent ChatGPT/Codex use outside the session can therefore skew it upward. If multiple independent root sessions run concurrently, the account delta is inherently indivisible and may be attributed to each active root. Polling can miss usage immediately before a reset, and OpenAI may round the source percentages. Inactive session totals stay frozen, and a resumed family refreshes before becoming active so unrelated idle-time usage is excluded. Last successful values provide the baseline through temporary request failures. Tokens and account identifiers are never exposed through plugin RPC or written to plugin storage; only quota values, session IDs, and a one-way account fingerprint are persisted.
|
||||||
|
|
||||||
## Uninstall
|
## Uninstall
|
||||||
|
|
||||||
Remove `plugins/stanp-opencode` from the selected config directory and remove any explicit configuration entry for it, then restart OpenCode.
|
Remove `plugins/stanp-opencode` from the selected config directory and remove any explicit configuration entry for it, then restart OpenCode.
|
||||||
|
|||||||
@@ -8,22 +8,31 @@
|
|||||||
"zod": "4.1.8",
|
"zod": "4.1.8",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@opencode/client": "0.0.0-beta-19378",
|
"@opencode/client": "2.0.2",
|
||||||
"@opencode/plugin": "0.0.0-beta-19378",
|
"@opencode/plugin": "2.0.2",
|
||||||
|
"@opencode/schema": "2.0.2",
|
||||||
|
"@opentui/core": "0.5.10",
|
||||||
|
"@opentui/solid": "0.5.10",
|
||||||
"@oxlint/plugins": "1.82.0",
|
"@oxlint/plugins": "1.82.0",
|
||||||
"@types/bun": "1.3.14",
|
"@types/bun": "1.3.14",
|
||||||
"oxfmt": "0.67.0",
|
"oxfmt": "0.67.0",
|
||||||
"oxlint": "1.82.0",
|
"oxlint": "1.82.0",
|
||||||
|
"solid-js": "1.9.15",
|
||||||
"typescript": "7.0.2",
|
"typescript": "7.0.2",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@opencode/plugin": "0.0.0-beta-19378",
|
"@opencode/plugin": "2.0.2",
|
||||||
|
"@opentui/core": ">=0.5.10",
|
||||||
|
"@opentui/solid": ">=0.5.10",
|
||||||
|
"solid-js": ">=1.9.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages": {
|
"packages": {
|
||||||
"@ai-sdk/provider": ["@ai-sdk/provider@3.0.8", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ=="],
|
"@ai-sdk/provider": ["@ai-sdk/provider@3.0.8", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ=="],
|
||||||
|
|
||||||
|
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
|
||||||
|
|
||||||
"@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/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
|
"@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
|
||||||
@@ -72,6 +81,62 @@
|
|||||||
|
|
||||||
"@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.3.0", "", {}, "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ=="],
|
"@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.3.0", "", {}, "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ=="],
|
||||||
|
|
||||||
|
"@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="],
|
||||||
|
|
||||||
|
"@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="],
|
||||||
|
|
||||||
|
"@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.29.8", "", { "dependencies": { "@babel/parser": "^7.29.8", "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg=="],
|
||||||
|
|
||||||
|
"@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" } }, "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw=="],
|
||||||
|
|
||||||
|
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.29.7", "", { "dependencies": { "@babel/compat-data": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g=="],
|
||||||
|
|
||||||
|
"@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-member-expression-to-functions": "^7.29.7", "@babel/helper-optimise-call-expression": "^7.29.7", "@babel/helper-replace-supers": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", "@babel/traverse": "^7.29.7", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg=="],
|
||||||
|
|
||||||
|
"@babel/helper-globals": ["@babel/helper-globals@7.29.7", "", {}, "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA=="],
|
||||||
|
|
||||||
|
"@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg=="],
|
||||||
|
|
||||||
|
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g=="],
|
||||||
|
|
||||||
|
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.29.7", "", { "dependencies": { "@babel/helper-module-imports": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg=="],
|
||||||
|
|
||||||
|
"@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" } }, "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong=="],
|
||||||
|
|
||||||
|
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.29.7", "", {}, "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw=="],
|
||||||
|
|
||||||
|
"@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.29.7", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.29.7", "@babel/helper-optimise-call-expression": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ=="],
|
||||||
|
|
||||||
|
"@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ=="],
|
||||||
|
|
||||||
|
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="],
|
||||||
|
|
||||||
|
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="],
|
||||||
|
|
||||||
|
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.29.7", "", {}, "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw=="],
|
||||||
|
|
||||||
|
"@babel/helpers": ["@babel/helpers@7.29.7", "", { "dependencies": { "@babel/template": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg=="],
|
||||||
|
|
||||||
|
"@babel/parser": ["@babel/parser@7.29.8", "", { "dependencies": { "@babel/types": "^7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA=="],
|
||||||
|
|
||||||
|
"@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A=="],
|
||||||
|
|
||||||
|
"@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA=="],
|
||||||
|
|
||||||
|
"@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.29.7", "", { "dependencies": { "@babel/helper-module-transforms": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ=="],
|
||||||
|
|
||||||
|
"@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-create-class-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", "@babel/plugin-syntax-typescript": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw=="],
|
||||||
|
|
||||||
|
"@babel/preset-typescript": ["@babel/preset-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ=="],
|
||||||
|
|
||||||
|
"@babel/template": ["@babel/template@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg=="],
|
||||||
|
|
||||||
|
"@babel/traverse": ["@babel/traverse@7.29.8", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.8", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.8", "@babel/template": "^7.29.7", "@babel/types": "^7.29.8", "debug": "^4.3.1" } }, "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg=="],
|
||||||
|
|
||||||
|
"@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="],
|
||||||
|
|
||||||
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-rc.112", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-node": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-web": ">=2.0.0 <3.0.0", "@opentelemetry/semantic-conventions": ">=1.33.0 <2.0.0", "effect": "^4.0.0-rc.112" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-OTRv1DxTHUmnakgJ6XVM8wVgF1KgZH4UXnOemwSLUwUjXO+RCikzF8oR/rlVmOGq81KtQzj1URM4M4nchlQOuQ=="],
|
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-rc.112", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-node": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-web": ">=2.0.0 <3.0.0", "@opentelemetry/semantic-conventions": ">=1.33.0 <2.0.0", "effect": "^4.0.0-rc.112" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-OTRv1DxTHUmnakgJ6XVM8wVgF1KgZH4UXnOemwSLUwUjXO+RCikzF8oR/rlVmOGq81KtQzj1URM4M4nchlQOuQ=="],
|
||||||
|
|
||||||
"@effect/platform-node": ["@effect/platform-node@4.0.0-rc.112", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.112", "mime": "^4.1.0", "undici": "^8.10.0" }, "peerDependencies": { "effect": "^4.0.0-rc.112", "redis": ">=5.0.0 <7.0.0" } }, "sha512-/BMAcdNGQQskLmI0Zoa95KfTZkr9HV9N4NSxaSrusG6GeW6Ulp9KvZ+Rlaiw8lnOt43CXjFLdfll5/k5rxL4hQ=="],
|
"@effect/platform-node": ["@effect/platform-node@4.0.0-rc.112", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.112", "mime": "^4.1.0", "undici": "^8.10.0" }, "peerDependencies": { "effect": "^4.0.0-rc.112", "redis": ">=5.0.0 <7.0.0" } }, "sha512-/BMAcdNGQQskLmI0Zoa95KfTZkr9HV9N4NSxaSrusG6GeW6Ulp9KvZ+Rlaiw8lnOt43CXjFLdfll5/k5rxL4hQ=="],
|
||||||
@@ -86,6 +151,14 @@
|
|||||||
|
|
||||||
"@isaacs/string-locale-compare": ["@isaacs/string-locale-compare@1.1.0", "", {}, "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ=="],
|
"@isaacs/string-locale-compare": ["@isaacs/string-locale-compare@1.1.0", "", {}, "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ=="],
|
||||||
|
|
||||||
|
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||||
|
|
||||||
|
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||||
|
|
||||||
|
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.6.0", "", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="],
|
||||||
|
|
||||||
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||||
|
|
||||||
"@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ=="],
|
"@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ=="],
|
||||||
|
|
||||||
"@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w=="],
|
"@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w=="],
|
||||||
@@ -128,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@0.0.0-beta-19378", "", { "dependencies": { "@aws-sdk/credential-providers": "3.1057.0", "@opencode/schema": "0.0.0-beta-19378", "@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-mk20W9+HH82jT8VLowhu9weV6Qkch+ydbfPRp2FJFh53RP9up1YaHLDu1o913biSJQNa36Q/9shln7YIOJ2PNA=="],
|
"@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/client": ["@opencode/client@0.0.0-beta-19378", "", { "dependencies": { "@opencode/protocol": "0.0.0-beta-19378", "@opencode/schema": "0.0.0-beta-19378" }, "peerDependencies": { "effect": "4.0.0-rc.112", "solid-js": ">=1.9.0" }, "optionalPeers": ["effect", "solid-js"] }, "sha512-tYhOVbCt4RFIxw3DYvX9NREomExR4QCE/K/mFoUxkU8dlhQNCDDT8ztztDkLyLycYwwvAJ+wKt4La6vH0/s8Pg=="],
|
"@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/plugin": ["@opencode/plugin@0.0.0-beta-19378", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@opencode/ai": "0.0.0-beta-19378", "@opencode/client": "0.0.0-beta-19378", "@opencode/protocol": "0.0.0-beta-19378", "@opencode/schema": "0.0.0-beta-19378", "@opencode/util": "0.0.0-beta-19378", "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112", "zod": "4.1.8" }, "peerDependencies": { "@opencode/theme": "0.0.0-beta-19378", "@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-Kzlp3gpem5QSzmEkrUOZPABnFy6a+m5wRGskXqt1KrJbXMIjrW9xnluFn81iHpiHEWRkQZOVZssw6VKPgyXQtA=="],
|
"@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/protocol": ["@opencode/protocol@0.0.0-beta-19378", "", { "dependencies": { "@opencode/schema": "0.0.0-beta-19378", "effect": "4.0.0-rc.112" } }, "sha512-BXh+ygV/xah3LYD12i0eVH69JW6m+7vVK7MiSUnKm+T88G8DT0ytJmqFcLYtoa1EcDNnujcmHMrLtHheTn4b4g=="],
|
"@opencode/protocol": ["@opencode/protocol@2.0.2", "", { "dependencies": { "@opencode/schema": "2.0.2", "effect": "4.0.0-rc.112" } }, "sha512-FxTxdHPNz46NkG8ZBB2S60QzXbZDlVEyZ6KeYTt2G7hcWB5JlMYBh8jeqHlsLbquKinvMKA2iuEsA1NaccN+YQ=="],
|
||||||
|
|
||||||
"@opencode/schema": ["@opencode/schema@0.0.0-beta-19378", "", { "dependencies": { "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112" } }, "sha512-aBilB58tyzWEE44gNmZXZpu5Xw2W3mNV3vrdKCX19z2VRoaZGY8BRhjDwFNGGBoZ9U5KXp9e0C0GKydUuKxT/w=="],
|
"@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/util": ["@opencode/util@0.0.0-beta-19378", "", { "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-YNAWKFt348p9UZWQJ5wyazTq8TOPrStaLnd7bA8m5E17CaULtKnxeiKBIcG095cpeqIZ+/JCQBurcqOZ7UbDrA=="],
|
"@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=="],
|
||||||
|
|
||||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||||
|
|
||||||
@@ -166,6 +239,26 @@
|
|||||||
|
|
||||||
"@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-darwin-arm64": ["@opentui/core-darwin-arm64@0.5.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Vyb+nTbhab8ZcRy5gg1loEEGwRcIbjAeVRIBfHBcbFDqmITBOg7x2gqJ+x/TnoOy4uwMhCmICUN2wiyREw3r1Q=="],
|
||||||
|
|
||||||
|
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.5.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-tTFLcM7Oj1gTyhm/bUdAt3C6grZdCxPk6+/g2azcZBUlI3/62LwbeRS6HbQKFFmm+1fUmX8cq6kWrtul885mVg=="],
|
||||||
|
|
||||||
|
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.5.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-ncJXcgudhBf2GdJyF3xVQN/Ec+1F7GOL+pRrURmgBYSj2v1w6EyoDQFAACtPTK2c3R38W6fvZwL4JSLlm4EFXQ=="],
|
||||||
|
|
||||||
|
"@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-x64": ["@opentui/core-linux-x64@0.5.10", "", { "os": "linux", "cpu": "x64" }, "sha512-5qtYaOgwVycZD1GaGshTRsi0rXPAmVExO03N1JQaHu+NYxK/vXSOc7Bu4QW0sPXx3Sp0SpzpP+FHjXABfoK66g=="],
|
||||||
|
|
||||||
|
"@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.5.10", "", { "os": "linux", "cpu": "x64" }, "sha512-Oj4H9hApuvuTKPWxh4SoZAgGJorR7vbvnrZA/cAkSMAk2VGSoHRRcqeXQbcH8IcdjVZ0KFpv8Zkl/D5Ye+2mew=="],
|
||||||
|
|
||||||
|
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.5.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-A9VhgvTxQoUdZ+8LmUumEng1sQNbj9QQQT3NYG9mSxI54qTANi7vOWNSphMiY6RMVsr22pgm6nUvSSvJXv7Jog=="],
|
||||||
|
|
||||||
|
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.5.10", "", { "os": "win32", "cpu": "x64" }, "sha512-u3KHa7kEeWrmKVDRJYpxSGO+g5E9cMGlrmTsPN3GVPHUmQMiREUawLXUvsU8+IHaQnqG3Q5nuE1yf4fPBzS+Qw=="],
|
||||||
|
|
||||||
|
"@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=="],
|
||||||
|
|
||||||
"@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.67.0", "", { "os": "android", "cpu": "arm" }, "sha512-2olh3ioEmc4gRzQm7jxyB1b/PFBoFvTq8KdgYySeNpysDtA6DEg2Mvya4/I6flhL7G0eOrE8RD7JCNCIMhE16Q=="],
|
||||||
|
|
||||||
"@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.67.0", "", { "os": "android", "cpu": "arm64" }, "sha512-ulfw8EHN1MBq/MFFDXw2/M1VAFu5mRUcnuZ8Hqbv9viAnFzO9t1jKSAsDqKYYDGMlytF/uj6Z5z5n/tHupnKhw=="],
|
||||||
@@ -370,10 +463,18 @@
|
|||||||
|
|
||||||
"aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="],
|
"aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="],
|
||||||
|
|
||||||
|
"babel-plugin-jsx-dom-expressions": ["babel-plugin-jsx-dom-expressions@0.40.10", "", { "dependencies": { "@babel/helper-module-imports": "7.18.6", "@babel/plugin-syntax-jsx": "^7.18.6", "@babel/types": "^7.20.7", "html-entities": "2.3.3", "parse5": "^7.1.2" }, "peerDependencies": { "@babel/core": "^7.20.12" } }, "sha512-lxve6Y02YiZTldB7efKpnbf1BH00XCFZNYYW235jSGsYaJNFtHrYlKV6/O+miHbjqpIr9FTe5+0no4hofAMbfA=="],
|
||||||
|
|
||||||
|
"babel-plugin-module-resolver": ["babel-plugin-module-resolver@5.0.2", "", { "dependencies": { "find-babel-config": "^2.1.1", "glob": "^9.3.3", "pkg-up": "^3.1.0", "reselect": "^4.1.7", "resolve": "^1.22.8" } }, "sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg=="],
|
||||||
|
|
||||||
|
"babel-preset-solid": ["babel-preset-solid@1.9.12", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.6" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.12" }, "optionalPeers": ["solid-js"] }, "sha512-LLqnuKVDlKpyBlMPcH6qEvs/wmS9a+NczppxJ3ryS/c0O5IiSFOIBQi9GzyiGDSbcJpx4Gr87jyFTos1MyEuWg=="],
|
||||||
|
|
||||||
"balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
|
"balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
|
||||||
|
|
||||||
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||||
|
|
||||||
|
"baseline-browser-mapping": ["baseline-browser-mapping@2.11.22", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-pWc4w51fBFd7mav43/zKRC+RI6f4yfzQoVlfvE8dECePyfkn1bzLp01Fj0QACcyCZyFhiEMyD2qScfKRWgWibA=="],
|
||||||
|
|
||||||
"bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
|
"bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
|
||||||
|
|
||||||
"bin-links": ["bin-links@6.0.2", "", { "dependencies": { "cmd-shim": "^8.0.0", "npm-normalize-package-bin": "^5.0.0", "proc-log": "^6.0.0", "read-cmd-shim": "^6.0.0", "write-file-atomic": "^7.0.0" } }, "sha512-frE1t78WOwJ45PKV2cF2tNPjTcs9L1J9s6VkrV59wanRP4GlaomuxYPVma7BwthMg8WnfSory4w5PTE6FZZ81w=="],
|
"bin-links": ["bin-links@6.0.2", "", { "dependencies": { "cmd-shim": "^8.0.0", "npm-normalize-package-bin": "^5.0.0", "proc-log": "^6.0.0", "read-cmd-shim": "^6.0.0", "write-file-atomic": "^7.0.0" } }, "sha512-frE1t78WOwJ45PKV2cF2tNPjTcs9L1J9s6VkrV59wanRP4GlaomuxYPVma7BwthMg8WnfSory4w5PTE6FZZ81w=="],
|
||||||
@@ -382,12 +483,18 @@
|
|||||||
|
|
||||||
"brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="],
|
"brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="],
|
||||||
|
|
||||||
|
"browserslist": ["browserslist@4.28.9", "", { "dependencies": { "baseline-browser-mapping": "^2.11.20", "caniuse-lite": "^1.0.30001810", "electron-to-chromium": "^1.5.420", "node-releases": "^2.0.54", "update-browserslist-db": "^1.3.2" }, "bin": { "browserslist": "cli.js" } }, "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg=="],
|
||||||
|
|
||||||
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
||||||
|
|
||||||
|
"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.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
||||||
|
|
||||||
"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=="],
|
||||||
|
|
||||||
|
"caniuse-lite": ["caniuse-lite@1.0.30001810", "", {}, "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg=="],
|
||||||
|
|
||||||
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
||||||
|
|
||||||
"ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="],
|
"ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="],
|
||||||
@@ -404,26 +511,40 @@
|
|||||||
|
|
||||||
"content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="],
|
"content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="],
|
||||||
|
|
||||||
|
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
||||||
|
|
||||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||||
|
|
||||||
"cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
|
"cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
|
||||||
|
|
||||||
|
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
||||||
|
|
||||||
"data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
|
"data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
|
||||||
|
|
||||||
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||||
|
|
||||||
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
||||||
|
|
||||||
|
"diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="],
|
||||||
|
|
||||||
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||||
|
|
||||||
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
|
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
|
||||||
|
|
||||||
"effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="],
|
"effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="],
|
||||||
|
|
||||||
"emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
"electron-to-chromium": ["electron-to-chromium@1.5.427", "", {}, "sha512-n14zb3FdsChZ2BNobqNHAJMcP3ifFv4paox2LvCrfVAQcqGiSURgbJl+PfMpHVCNFkStnNc+RRVtPBTVW5PDgw=="],
|
||||||
|
|
||||||
|
"emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
|
||||||
|
|
||||||
|
"entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
|
||||||
|
|
||||||
"env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="],
|
"env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="],
|
||||||
|
|
||||||
|
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
||||||
|
|
||||||
|
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||||
|
|
||||||
"exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="],
|
"exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="],
|
||||||
|
|
||||||
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
|
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
|
||||||
@@ -434,16 +555,28 @@
|
|||||||
|
|
||||||
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
|
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
|
||||||
|
|
||||||
|
"find-babel-config": ["find-babel-config@2.1.2", "", { "dependencies": { "json5": "^2.2.3" } }, "sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg=="],
|
||||||
|
|
||||||
|
"find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="],
|
||||||
|
|
||||||
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
||||||
|
|
||||||
"formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
|
"formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
|
||||||
|
|
||||||
"fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="],
|
"fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="],
|
||||||
|
|
||||||
|
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
|
||||||
|
|
||||||
|
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||||
|
|
||||||
"gaxios": ["gaxios@7.3.1", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2" } }, "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ=="],
|
"gaxios": ["gaxios@7.3.1", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2" } }, "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ=="],
|
||||||
|
|
||||||
"gcp-metadata": ["gcp-metadata@8.1.4", "", { "dependencies": { "gaxios": "7.1.3", "google-logging-utils": "1.1.3", "json-bigint": "^1.0.0" } }, "sha512-iJ9KMsiu+xKtNRX0PmGLSaIU3bUBAyzWTyqKemKPzNPsmmsBCQYmlNg+brEbES7IHSXtdVwzBPzx1vz3FAaipw=="],
|
"gcp-metadata": ["gcp-metadata@8.1.4", "", { "dependencies": { "gaxios": "7.1.3", "google-logging-utils": "1.1.3", "json-bigint": "^1.0.0" } }, "sha512-iJ9KMsiu+xKtNRX0PmGLSaIU3bUBAyzWTyqKemKPzNPsmmsBCQYmlNg+brEbES7IHSXtdVwzBPzx1vz3FAaipw=="],
|
||||||
|
|
||||||
|
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
|
||||||
|
|
||||||
|
"get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="],
|
||||||
|
|
||||||
"glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="],
|
"glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="],
|
||||||
|
|
||||||
"google-auth-library": ["google-auth-library@10.5.0", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.0.0", "gcp-metadata": "^8.0.0", "google-logging-utils": "^1.0.0", "gtoken": "^8.0.0", "jws": "^4.0.0" } }, "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w=="],
|
"google-auth-library": ["google-auth-library@10.5.0", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.0.0", "gcp-metadata": "^8.0.0", "google-logging-utils": "^1.0.0", "gtoken": "^8.0.0", "jws": "^4.0.0" } }, "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w=="],
|
||||||
@@ -454,8 +587,12 @@
|
|||||||
|
|
||||||
"gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="],
|
"gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="],
|
||||||
|
|
||||||
|
"hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="],
|
||||||
|
|
||||||
"hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="],
|
"hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="],
|
||||||
|
|
||||||
|
"html-entities": ["html-entities@2.3.3", "", {}, "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="],
|
||||||
|
|
||||||
"http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="],
|
"http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="],
|
||||||
|
|
||||||
"http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
|
"http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
|
||||||
@@ -470,12 +607,18 @@
|
|||||||
|
|
||||||
"ip-address": ["ip-address@10.7.0", "", {}, "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA=="],
|
"ip-address": ["ip-address@10.7.0", "", {}, "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA=="],
|
||||||
|
|
||||||
|
"is-core-module": ["is-core-module@2.16.2", "", { "dependencies": { "hasown": "^2.0.3" } }, "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA=="],
|
||||||
|
|
||||||
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||||
|
|
||||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||||
|
|
||||||
"jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
|
"jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
|
||||||
|
|
||||||
|
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||||
|
|
||||||
|
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
|
||||||
|
|
||||||
"json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="],
|
"json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="],
|
||||||
|
|
||||||
"json-parse-even-better-errors": ["json-parse-even-better-errors@5.0.0", "", {}, "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ=="],
|
"json-parse-even-better-errors": ["json-parse-even-better-errors@5.0.0", "", {}, "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ=="],
|
||||||
@@ -484,6 +627,8 @@
|
|||||||
|
|
||||||
"json-stringify-nice": ["json-stringify-nice@1.1.4", "", {}, "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw=="],
|
"json-stringify-nice": ["json-stringify-nice@1.1.4", "", {}, "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw=="],
|
||||||
|
|
||||||
|
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
||||||
|
|
||||||
"jsonparse": ["jsonparse@1.3.1", "", {}, "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="],
|
"jsonparse": ["jsonparse@1.3.1", "", {}, "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="],
|
||||||
|
|
||||||
"just-diff": ["just-diff@6.0.2", "", {}, "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA=="],
|
"just-diff": ["just-diff@6.0.2", "", {}, "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA=="],
|
||||||
@@ -494,12 +639,16 @@
|
|||||||
|
|
||||||
"jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="],
|
"jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="],
|
||||||
|
|
||||||
|
"locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="],
|
||||||
|
|
||||||
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
||||||
|
|
||||||
"lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="],
|
"lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="],
|
||||||
|
|
||||||
"make-fetch-happen": ["make-fetch-happen@15.0.6", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/agent": "^4.0.0", "@npmcli/redact": "^4.0.0", "cacache": "^20.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^6.0.0", "ssri": "^13.0.0" } }, "sha512-Je0fLJ0F5atA7F+eIlLzk+Wkcl57JDf4kf+EW8xiP5E31xOQxkIxTbgf1Oi1Lw9tRI9UEMRdI5Vz2xTzoNU1Jw=="],
|
"make-fetch-happen": ["make-fetch-happen@15.0.6", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/agent": "^4.0.0", "@npmcli/redact": "^4.0.0", "cacache": "^20.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^6.0.0", "ssri": "^13.0.0" } }, "sha512-Je0fLJ0F5atA7F+eIlLzk+Wkcl57JDf4kf+EW8xiP5E31xOQxkIxTbgf1Oi1Lw9tRI9UEMRdI5Vz2xTzoNU1Jw=="],
|
||||||
|
|
||||||
|
"marked": ["marked@17.0.1", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg=="],
|
||||||
|
|
||||||
"mime": ["mime@4.1.0", "", { "bin": { "mime": "bin/cli.js" } }, "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw=="],
|
"mime": ["mime@4.1.0", "", { "bin": { "mime": "bin/cli.js" } }, "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw=="],
|
||||||
|
|
||||||
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
@@ -538,6 +687,8 @@
|
|||||||
|
|
||||||
"node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="],
|
"node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="],
|
||||||
|
|
||||||
|
"node-releases": ["node-releases@2.0.55", "", {}, "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ=="],
|
||||||
|
|
||||||
"nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="],
|
"nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="],
|
||||||
|
|
||||||
"npm-bundled": ["npm-bundled@5.0.0", "", { "dependencies": { "npm-normalize-package-bin": "^5.0.0" } }, "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw=="],
|
"npm-bundled": ["npm-bundled@5.0.0", "", { "dependencies": { "npm-normalize-package-bin": "^5.0.0" } }, "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw=="],
|
||||||
@@ -558,20 +709,36 @@
|
|||||||
|
|
||||||
"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.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=="],
|
||||||
|
|
||||||
|
"p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
|
||||||
|
|
||||||
|
"p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="],
|
||||||
|
|
||||||
"p-map": ["p-map@7.0.7", "", {}, "sha512-VaWRu2i4FJNRtiRWCuuQRgfQ1B7a6+gMSrO+3j0EQi/k0ULfS9kosRxGoiqwzIjZTDI02tGfk5mXXltLg6QtfQ=="],
|
"p-map": ["p-map@7.0.7", "", {}, "sha512-VaWRu2i4FJNRtiRWCuuQRgfQ1B7a6+gMSrO+3j0EQi/k0ULfS9kosRxGoiqwzIjZTDI02tGfk5mXXltLg6QtfQ=="],
|
||||||
|
|
||||||
|
"p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="],
|
||||||
|
|
||||||
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
|
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
|
||||||
|
|
||||||
"pacote": ["pacote@21.5.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/git": "^7.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "@npmcli/run-script": "^10.0.0", "cacache": "^20.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^13.0.0", "npm-packlist": "^10.0.1", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "sigstore": "^4.0.0", "ssri": "^13.0.0", "tar": "^7.4.3" }, "bin": { "pacote": "bin/index.js" } }, "sha512-KvcJ9iy3crysCsgqc4+PknH/w6jkrp8JN36mpZBPwNaDRwTfMZD37YzRazNstiZUOhuF5pno9f78n9mEJBavwg=="],
|
"pacote": ["pacote@21.5.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/git": "^7.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "@npmcli/run-script": "^10.0.0", "cacache": "^20.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^13.0.0", "npm-packlist": "^10.0.1", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "sigstore": "^4.0.0", "ssri": "^13.0.0", "tar": "^7.4.3" }, "bin": { "pacote": "bin/index.js" } }, "sha512-KvcJ9iy3crysCsgqc4+PknH/w6jkrp8JN36mpZBPwNaDRwTfMZD37YzRazNstiZUOhuF5pno9f78n9mEJBavwg=="],
|
||||||
|
|
||||||
"parse-conflict-json": ["parse-conflict-json@5.0.1", "", { "dependencies": { "json-parse-even-better-errors": "^5.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" } }, "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ=="],
|
"parse-conflict-json": ["parse-conflict-json@5.0.1", "", { "dependencies": { "json-parse-even-better-errors": "^5.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" } }, "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ=="],
|
||||||
|
|
||||||
|
"parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
|
||||||
|
|
||||||
|
"path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="],
|
||||||
|
|
||||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||||
|
|
||||||
|
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
|
||||||
|
|
||||||
"path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
|
"path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
|
||||||
|
|
||||||
|
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||||
|
|
||||||
"picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="],
|
"picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="],
|
||||||
|
|
||||||
|
"pkg-up": ["pkg-up@3.1.0", "", { "dependencies": { "find-up": "^3.0.0" } }, "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA=="],
|
||||||
|
|
||||||
"postcss-selector-parser": ["postcss-selector-parser@7.1.6", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw=="],
|
"postcss-selector-parser": ["postcss-selector-parser@7.1.6", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw=="],
|
||||||
|
|
||||||
"proc-log": ["proc-log@6.1.0", "", {}, "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ=="],
|
"proc-log": ["proc-log@6.1.0", "", {}, "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ=="],
|
||||||
@@ -590,13 +757,23 @@
|
|||||||
|
|
||||||
"redis": ["redis@6.2.1", "", { "dependencies": { "@redis/bloom": "6.2.1", "@redis/client": "6.2.1", "@redis/json": "6.2.1", "@redis/search": "6.2.1", "@redis/time-series": "6.2.1" } }, "sha512-Z9VHtgYs48PiQC77X9O2Er8Hj4T+5BtFjT91/vi5Is1D04N72cA946ZslM1ImJw8ZctFBZWAVjM7S5wJNeHMpg=="],
|
"redis": ["redis@6.2.1", "", { "dependencies": { "@redis/bloom": "6.2.1", "@redis/client": "6.2.1", "@redis/json": "6.2.1", "@redis/search": "6.2.1", "@redis/time-series": "6.2.1" } }, "sha512-Z9VHtgYs48PiQC77X9O2Er8Hj4T+5BtFjT91/vi5Is1D04N72cA946ZslM1ImJw8ZctFBZWAVjM7S5wJNeHMpg=="],
|
||||||
|
|
||||||
|
"reselect": ["reselect@4.1.8", "", {}, "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ=="],
|
||||||
|
|
||||||
|
"resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="],
|
||||||
|
|
||||||
"rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="],
|
"rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="],
|
||||||
|
|
||||||
|
"s-js": ["s-js@0.4.9", "", {}, "sha512-RtpOm+cM6O0sHg6IA70wH+UC3FZcND+rccBZpBAHzlUgNO2Bm5BN+FnM8+OBxzXdwpKWFwX11JGF0MFRkhSoIQ=="],
|
||||||
|
|
||||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||||
|
|
||||||
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||||
|
|
||||||
"semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||||
|
|
||||||
|
"seroval": ["seroval@1.5.6", "", {}, "sha512-rVQVWjjSvlINzaQPZH5JFqsqEsIWdTxY3iJZCnTL/5gQbXIRooVZKI60tVCkOVfzcRPejboxO2t0P89dg5mQaA=="],
|
||||||
|
|
||||||
|
"seroval-plugins": ["seroval-plugins@1.5.6", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-HXuLAX2pu/UByPpaeo/TaMfvMIi+1QqIoPJYCcAtU8QkVNwgR6MPlGuCQTErV1JwraaMbYaWVIBX7mppzGLATQ=="],
|
||||||
|
|
||||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||||
|
|
||||||
@@ -612,6 +789,8 @@
|
|||||||
|
|
||||||
"socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="],
|
"socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="],
|
||||||
|
|
||||||
|
"solid-js": ["solid-js@1.9.15", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.4", "seroval-plugins": "~1.5.4" } }, "sha512-EeiY2xfpZJqPLjXspVEKjAII4yv8NyG//NxZ3IpOFHdUNnnTyL0uJOeS9LWGvA7cFCz5y94cjFwYlmw5Luncsg=="],
|
||||||
|
|
||||||
"spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="],
|
"spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="],
|
||||||
|
|
||||||
"spdx-expression-parse": ["spdx-expression-parse@4.0.0", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ=="],
|
"spdx-expression-parse": ["spdx-expression-parse@4.0.0", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ=="],
|
||||||
@@ -620,14 +799,16 @@
|
|||||||
|
|
||||||
"ssri": ["ssri@13.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ=="],
|
"ssri": ["ssri@13.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ=="],
|
||||||
|
|
||||||
"string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
"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-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
"string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||||
|
|
||||||
"strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
|
"strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
|
||||||
|
|
||||||
"strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
"strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
|
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
|
||||||
|
|
||||||
"tar": ["tar@7.5.22", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA=="],
|
"tar": ["tar@7.5.22", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA=="],
|
||||||
|
|
||||||
"tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="],
|
"tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="],
|
||||||
@@ -646,6 +827,8 @@
|
|||||||
|
|
||||||
"undici-types": ["undici-types@8.9.0", "", {}, "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg=="],
|
"undici-types": ["undici-types@8.9.0", "", {}, "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg=="],
|
||||||
|
|
||||||
|
"update-browserslist-db": ["update-browserslist-db@1.3.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ=="],
|
||||||
|
|
||||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||||
|
|
||||||
"validate-npm-package-name": ["validate-npm-package-name@7.0.2", "", {}, "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A=="],
|
"validate-npm-package-name": ["validate-npm-package-name@7.0.2", "", {}, "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A=="],
|
||||||
@@ -654,6 +837,8 @@
|
|||||||
|
|
||||||
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
|
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
|
||||||
|
|
||||||
|
"web-tree-sitter": ["web-tree-sitter@0.25.10", "", { "peerDependencies": { "@types/emscripten": "^1.40.0" }, "optionalPeers": ["@types/emscripten"] }, "sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA=="],
|
||||||
|
|
||||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||||
|
|
||||||
"wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
|
"wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
|
||||||
@@ -672,10 +857,32 @@
|
|||||||
|
|
||||||
"@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/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
|
||||||
|
|
||||||
|
"@npmcli/arborist/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
|
|
||||||
|
"@npmcli/config/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
|
|
||||||
|
"@npmcli/fs/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
|
|
||||||
|
"@npmcli/git/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
|
|
||||||
"@npmcli/git/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="],
|
"@npmcli/git/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="],
|
||||||
|
|
||||||
|
"@npmcli/metavuln-calculator/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
|
|
||||||
|
"@npmcli/package-json/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
|
|
||||||
"@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=="],
|
||||||
|
|
||||||
|
"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=="],
|
||||||
|
|
||||||
"gcp-metadata/gaxios": ["gaxios@7.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2", "rimraf": "^5.0.1" } }, "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ=="],
|
"gcp-metadata/gaxios": ["gaxios@7.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2", "rimraf": "^5.0.1" } }, "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ=="],
|
||||||
|
|
||||||
"gcp-metadata/google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="],
|
"gcp-metadata/google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="],
|
||||||
@@ -684,18 +891,34 @@
|
|||||||
|
|
||||||
"minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
"minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
|
|
||||||
|
"node-gyp/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
|
|
||||||
"node-gyp/undici": ["undici@6.28.1", "", {}, "sha512-zWpdTVD54H48CIybL0rWQ3ukpb9d23wM7eH5RtfdmeP70cWHNjtfo7P4vZX+5CoDcO53J4Pu5uXp7lNfjc6DRA=="],
|
"node-gyp/undici": ["undici@6.28.1", "", {}, "sha512-zWpdTVD54H48CIybL0rWQ3ukpb9d23wM7eH5RtfdmeP70cWHNjtfo7P4vZX+5CoDcO53J4Pu5uXp7lNfjc6DRA=="],
|
||||||
|
|
||||||
"node-gyp/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="],
|
"node-gyp/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="],
|
||||||
|
|
||||||
|
"npm-install-checks/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
|
|
||||||
|
"npm-package-arg/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
|
|
||||||
|
"npm-pick-manifest/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
|
|
||||||
|
"parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
|
||||||
|
|
||||||
"rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
|
"rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
|
||||||
|
|
||||||
|
"string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
|
||||||
|
|
||||||
"string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
"string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||||
|
|
||||||
"string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
"string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
|
"wrap-ansi/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
||||||
|
|
||||||
|
"wrap-ansi/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
|
||||||
|
|
||||||
"wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
"wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||||
|
|
||||||
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||||
@@ -706,10 +929,20 @@
|
|||||||
|
|
||||||
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
|
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
|
||||||
|
|
||||||
|
"@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||||
|
|
||||||
|
"@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
||||||
|
|
||||||
"@npmcli/git/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="],
|
"@npmcli/git/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="],
|
||||||
|
|
||||||
"@npmcli/promise-spawn/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="],
|
"@npmcli/promise-spawn/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="],
|
||||||
|
|
||||||
|
"babel-plugin-module-resolver/glob/minimatch": ["minimatch@8.0.7", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg=="],
|
||||||
|
|
||||||
|
"babel-plugin-module-resolver/glob/minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="],
|
||||||
|
|
||||||
|
"babel-plugin-module-resolver/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
|
||||||
|
|
||||||
"minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
"minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
"minipass-pipeline/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
"minipass-pipeline/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
@@ -726,10 +959,20 @@
|
|||||||
|
|
||||||
"wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
"wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
|
"wrap-ansi/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
||||||
|
|
||||||
|
"babel-plugin-module-resolver/glob/minimatch/brace-expansion": ["brace-expansion@2.1.4", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg=="],
|
||||||
|
|
||||||
|
"babel-plugin-module-resolver/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||||
|
|
||||||
|
"babel-plugin-module-resolver/glob/path-scurry/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
|
||||||
|
|
||||||
"rimraf/glob/minimatch/brace-expansion": ["brace-expansion@2.1.4", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg=="],
|
"rimraf/glob/minimatch/brace-expansion": ["brace-expansion@2.1.4", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg=="],
|
||||||
|
|
||||||
"rimraf/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
"rimraf/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||||
|
|
||||||
|
"babel-plugin-module-resolver/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||||
|
|
||||||
"rimraf/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
"rimraf/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
+79
@@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
for command in bun jq; do
|
||||||
|
command -v "$command" >/dev/null || { printf 'Required command not found: %s\n' "$command" >&2; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
checkout=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)
|
||||||
|
config="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}"
|
||||||
|
mkdir -p "$config"
|
||||||
|
config=$(cd "$config" && pwd -P)
|
||||||
|
mkdir -p "$config/plugins"
|
||||||
|
install=$(mktemp -d "$config/install.stanp-opencode.XXXXXXXX")
|
||||||
|
staged=""
|
||||||
|
backup=""
|
||||||
|
cleanup() {
|
||||||
|
[[ -z "$install" ]] || rm -rf "$install"
|
||||||
|
[[ -z "$staged" ]] || rm -rf "$staged"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
(cd "$checkout" && bun install --frozen-lockfile && bun run build)
|
||||||
|
|
||||||
|
bun -e '
|
||||||
|
if (!await Bun.file(process.argv[1]).exists()) {
|
||||||
|
throw new Error("Local build lacks the OpenCode V2 directory entrypoint.");
|
||||||
|
}
|
||||||
|
const { default: plugin } = await import(process.argv[1]);
|
||||||
|
if (!plugin || plugin.id !== "stanp-opencode" || typeof plugin.setup !== "function") {
|
||||||
|
throw new Error("Local build is not a native OpenCode V2 plugin.");
|
||||||
|
}
|
||||||
|
const tuiFile = Bun.file(process.argv[2]);
|
||||||
|
const manifest = await Bun.file(process.argv[3]).json();
|
||||||
|
const exportsTui = manifest?.exports?.["./tui"];
|
||||||
|
if (!await tuiFile.exists() || !new Bun.Transpiler({ loader: "js" }).scan(await tuiFile.text()).exports.includes("default") || (typeof exportsTui !== "string" && typeof exportsTui?.import !== "string")) {
|
||||||
|
throw new Error("Local build lacks the ChatGPT quota TUI plugin.");
|
||||||
|
}
|
||||||
|
' "$checkout/dist/index.js" "$checkout/dist/tui.js" "$checkout/package.json"
|
||||||
|
|
||||||
|
config_file="$config/opencode.json"
|
||||||
|
config_source="$config_file"
|
||||||
|
if [[ ! -e "$config_source" ]]; then
|
||||||
|
config_source="$install/empty-config.json"
|
||||||
|
printf '{}\n' > "$config_source"
|
||||||
|
fi
|
||||||
|
jq -e '
|
||||||
|
if type != "object" then error("opencode.json must contain an object") else . end
|
||||||
|
| if (.plugins // []) | type != "array" then error("opencode.json plugins must be an array") else . end
|
||||||
|
| .["$schema"] = (.["$schema"] // "https://opencode.ai/config.json")
|
||||||
|
| .plugins = (.plugins // [])
|
||||||
|
| if any(.plugins[]?; .package == "./plugins/stanp-opencode") then . else
|
||||||
|
.plugins += [{
|
||||||
|
package: "./plugins/stanp-opencode",
|
||||||
|
options: { mode: "gpt", provider: "openai", lunaPriority: true }
|
||||||
|
}]
|
||||||
|
end
|
||||||
|
' "$config_source" > "$install/opencode.json"
|
||||||
|
|
||||||
|
target="$config/plugins/stanp-opencode"
|
||||||
|
staged="$config/plugins/.stanp-opencode.new.$$"
|
||||||
|
backup="$config/plugins/.stanp-opencode.old.$$"
|
||||||
|
mkdir "$staged"
|
||||||
|
cp "$checkout/dist/index.js" "$staged/index.js"
|
||||||
|
cp "$checkout/dist/tui.js" "$staged/tui.js"
|
||||||
|
cat > "$staged/package.json" <<'EOF'
|
||||||
|
{"name":"stanp-opencode","type":"module","main":"./index.js","exports":{".":"./index.js","./tui":"./tui.js"}}
|
||||||
|
EOF
|
||||||
|
if [[ -e "$target" || -L "$target" ]]; then mv "$target" "$backup"; fi
|
||||||
|
if ! mv "$staged" "$target"; then
|
||||||
|
if [[ -e "$backup" || -L "$backup" ]]; then mv "$backup" "$target"; fi
|
||||||
|
printf 'Could not activate plugin; installation unchanged\n' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
staged=""
|
||||||
|
rm -rf "$backup"
|
||||||
|
backup=""
|
||||||
|
rm -f "$config/plugins/stanp-opencode.js"
|
||||||
|
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"
|
||||||
+9
-2
@@ -42,7 +42,13 @@ bun -e '
|
|||||||
if (!plugin || plugin.id !== "stanp-opencode" || typeof plugin.setup !== "function") {
|
if (!plugin || plugin.id !== "stanp-opencode" || typeof plugin.setup !== "function") {
|
||||||
throw new Error("Latest release is not a native OpenCode V2 plugin. Publish a V2-compatible release first.");
|
throw new Error("Latest release is not a native OpenCode V2 plugin. Publish a V2-compatible release first.");
|
||||||
}
|
}
|
||||||
' "$install/package/dist/index.js"
|
const tuiFile = Bun.file(process.argv[2]);
|
||||||
|
const manifest = await Bun.file(process.argv[3]).json();
|
||||||
|
const exportsTui = manifest?.exports?.["./tui"];
|
||||||
|
if (!await tuiFile.exists() || !new Bun.Transpiler({ loader: "js" }).scan(await tuiFile.text()).exports.includes("default") || (typeof exportsTui !== "string" && typeof exportsTui?.import !== "string")) {
|
||||||
|
throw new Error("Latest release lacks the ChatGPT quota TUI plugin.");
|
||||||
|
}
|
||||||
|
' "$install/package/dist/index.js" "$install/package/dist/tui.js" "$install/package/package.json"
|
||||||
|
|
||||||
tag=$(jq -r '.tag_name' "$install/release.json")
|
tag=$(jq -r '.tag_name' "$install/release.json")
|
||||||
config_file="$config/opencode.json"
|
config_file="$config/opencode.json"
|
||||||
@@ -68,8 +74,9 @@ staged="$config/plugins/.stanp-opencode.new.$$"
|
|||||||
backup="$config/plugins/.stanp-opencode.old.$$"
|
backup="$config/plugins/.stanp-opencode.old.$$"
|
||||||
mkdir "$staged"
|
mkdir "$staged"
|
||||||
mv "$install/package/dist/index.js" "$staged/index.js"
|
mv "$install/package/dist/index.js" "$staged/index.js"
|
||||||
|
mv "$install/package/dist/tui.js" "$staged/tui.js"
|
||||||
cat > "$staged/package.json" <<'EOF'
|
cat > "$staged/package.json" <<'EOF'
|
||||||
{"name":"stanp-opencode","type":"module","main":"./index.js","exports":"./index.js"}
|
{"name":"stanp-opencode","type":"module","main":"./index.js","exports":{".":"./index.js","./tui":"./tui.js"}}
|
||||||
EOF
|
EOF
|
||||||
if [[ -e "$target" || -L "$target" ]]; then mv "$target" "$backup"; fi
|
if [[ -e "$target" || -L "$target" ]]; then mv "$target" "$backup"; fi
|
||||||
if ! mv "$staged" "$target"; then
|
if ! mv "$staged" "$target"; then
|
||||||
|
|||||||
+20
-5
@@ -9,6 +9,14 @@
|
|||||||
".": {
|
".": {
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"import": "./dist/index.js"
|
"import": "./dist/index.js"
|
||||||
|
},
|
||||||
|
"./tui": {
|
||||||
|
"types": "./dist/tui.d.ts",
|
||||||
|
"import": "./dist/tui.js"
|
||||||
|
},
|
||||||
|
"./quota-rpc": {
|
||||||
|
"types": "./dist/quota-rpc.d.ts",
|
||||||
|
"import": "./dist/quota-rpc.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
@@ -25,20 +33,27 @@
|
|||||||
"lint": "oxlint --deny-warnings .",
|
"lint": "oxlint --deny-warnings .",
|
||||||
"format": "oxfmt --write .",
|
"format": "oxfmt --write .",
|
||||||
"format:check": "oxfmt --check .",
|
"format:check": "oxfmt --check .",
|
||||||
"test": "bun test",
|
"test": "bun test --conditions=browser",
|
||||||
"build": "bun build src/index.ts --outdir dist --target bun --format esm && tsc --project tsconfig.build.json --emitDeclarationOnly"
|
"build": "bun scripts/build.ts && tsc --project tsconfig.build.json --emitDeclarationOnly"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@opencode/client": "0.0.0-beta-19378",
|
"@opencode/client": "2.0.2",
|
||||||
"@opencode/plugin": "0.0.0-beta-19378",
|
"@opencode/plugin": "2.0.2",
|
||||||
|
"@opencode/schema": "2.0.2",
|
||||||
|
"@opentui/core": "0.5.10",
|
||||||
|
"@opentui/solid": "0.5.10",
|
||||||
"@oxlint/plugins": "1.82.0",
|
"@oxlint/plugins": "1.82.0",
|
||||||
"@types/bun": "1.3.14",
|
"@types/bun": "1.3.14",
|
||||||
"oxfmt": "0.67.0",
|
"oxfmt": "0.67.0",
|
||||||
"oxlint": "1.82.0",
|
"oxlint": "1.82.0",
|
||||||
|
"solid-js": "1.9.15",
|
||||||
"typescript": "7.0.2"
|
"typescript": "7.0.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@opencode/plugin": "0.0.0-beta-19378"
|
"@opencode/plugin": "2.0.2",
|
||||||
|
"@opentui/core": ">=0.5.10",
|
||||||
|
"@opentui/solid": ">=0.5.10",
|
||||||
|
"solid-js": ">=1.9.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"zod": "4.1.8"
|
"zod": "4.1.8"
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import solidPlugin from "@opentui/solid/bun-plugin";
|
||||||
|
|
||||||
|
export async function build() {
|
||||||
|
const results = await Promise.all([
|
||||||
|
Bun.build({
|
||||||
|
entrypoints: ["src/index.ts", "src/quota-rpc.ts"],
|
||||||
|
outdir: "dist",
|
||||||
|
target: "bun",
|
||||||
|
format: "esm",
|
||||||
|
}),
|
||||||
|
Bun.build({
|
||||||
|
entrypoints: ["src/tui.tsx"],
|
||||||
|
outdir: "dist",
|
||||||
|
target: "bun",
|
||||||
|
format: "esm",
|
||||||
|
external: ["@opencode/plugin/tui", "@opentui/solid", "solid-js"],
|
||||||
|
plugins: [solidPlugin],
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (const result of results) {
|
||||||
|
if (result.success) continue;
|
||||||
|
for (const log of result.logs) console.error(log);
|
||||||
|
throw new Error("Build failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (import.meta.main) await build();
|
||||||
+35
-1
@@ -1,9 +1,12 @@
|
|||||||
import { Agent, Model, Plugin, Provider } from "@opencode/plugin";
|
import { Agent, Model, Plugin, Provider } from "@opencode/plugin";
|
||||||
|
import type { RpcRegistration } from "@opencode/plugin/promise/rpc";
|
||||||
import type { ModelInfo } from "@opencode/client";
|
import type { ModelInfo } from "@opencode/client";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { gptAgents, settings, workerNames } from "./config.js";
|
import { gptAgents, settings, workerNames } from "./config.js";
|
||||||
import { discover } from "./provider.js";
|
import { discover } from "./provider.js";
|
||||||
import { descriptions, routingGuide } from "./routing.js";
|
import { descriptions, routingGuide } from "./routing.js";
|
||||||
|
import { QuotaTracker } from "./quota.js";
|
||||||
|
import { QuotaRpc } from "./quota-rpc.js";
|
||||||
|
|
||||||
// Permission actions use wildcards, not filesystem globs.
|
// Permission actions use wildcards, not filesystem globs.
|
||||||
function matches(value: string, pattern: string) {
|
function matches(value: string, pattern: string) {
|
||||||
@@ -50,10 +53,24 @@ export default Plugin.define({
|
|||||||
let codegraphTools: string[] = [];
|
let codegraphTools: string[] = [];
|
||||||
let agentTransformReady = false;
|
let agentTransformReady = false;
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
|
let quotaRegistration: RpcRegistration<typeof QuotaRpc> | undefined;
|
||||||
|
const quota = new QuotaTracker(context, async () => {
|
||||||
|
await quotaRegistration?.events.emit("updated", {});
|
||||||
|
});
|
||||||
|
quotaRegistration = await context.rpc.register(QuotaRpc, {
|
||||||
|
status: async ({ sessionID }) => (await quota.status(sessionID)) ?? null,
|
||||||
|
});
|
||||||
|
await quota.init();
|
||||||
// Subscribe before the first read: configuration can publish its catalog while
|
// Subscribe before the first read: configuration can publish its catalog 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 (
|
||||||
|
event.location &&
|
||||||
|
(event.location.directory !== context.location.directory ||
|
||||||
|
event.location.workspaceID !== context.location.workspaceID)
|
||||||
|
)
|
||||||
|
continue;
|
||||||
if (event.type === "catalog.updated") {
|
if (event.type === "catalog.updated") {
|
||||||
models = await discover(context, selected.provider);
|
models = await discover(context, selected.provider);
|
||||||
await context.agent.reload();
|
await context.agent.reload();
|
||||||
@@ -69,6 +86,20 @@ export default Plugin.define({
|
|||||||
inherited = permissions;
|
inherited = permissions;
|
||||||
permissionKey = key;
|
permissionKey = key;
|
||||||
await context.agent.reload();
|
await context.agent.reload();
|
||||||
|
} else if (
|
||||||
|
event.type === "session.execution.succeeded" ||
|
||||||
|
event.type === "session.execution.failed" ||
|
||||||
|
event.type === "session.execution.interrupted" ||
|
||||||
|
event.type === "session.idle"
|
||||||
|
) {
|
||||||
|
await quota.complete(event.data.sessionID);
|
||||||
|
} else if (event.type === "credential.updated") {
|
||||||
|
await quota.authChanged();
|
||||||
|
} else if (
|
||||||
|
event.type === "credential.switched" &&
|
||||||
|
String(event.data.integrationID) === "openai"
|
||||||
|
) {
|
||||||
|
await quota.authChanged(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})().catch((error) => {
|
})().catch((error) => {
|
||||||
@@ -198,7 +229,7 @@ export default Plugin.define({
|
|||||||
)?.effect ?? "ask";
|
)?.effect ?? "ask";
|
||||||
if (effect !== "allow")
|
if (effect !== "allow")
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`${action} requires an allow permission: OpenCode beta's public plugin API cannot request custom-tool permission approval (${effect}).`,
|
`${action} requires an allow permission: OpenCode's public plugin API cannot request custom-tool permission approval (${effect}).`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await context.tool.transform((editor) => {
|
await context.tool.transform((editor) => {
|
||||||
@@ -251,6 +282,7 @@ export default Plugin.define({
|
|||||||
properties: { ...properties, agent: { type: "string", enum: workers } },
|
properties: { ...properties, agent: { type: "string", enum: workers } },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
await context.session.hook("model.request", async (event) => quota.start(event.sessionID));
|
||||||
await context.tool.hook("execute.before", (event) => {
|
await context.tool.hook("execute.before", (event) => {
|
||||||
if (event.tool !== "subagent") return;
|
if (event.tool !== "subagent") return;
|
||||||
const { agent } = delegation.parse(event.input);
|
const { agent } = delegation.parse(event.input);
|
||||||
@@ -278,6 +310,8 @@ export default Plugin.define({
|
|||||||
return async () => {
|
return async () => {
|
||||||
controller.abort();
|
controller.abort();
|
||||||
await updates;
|
await updates;
|
||||||
|
await quota.dispose();
|
||||||
|
await quotaRegistration?.dispose();
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Rpc } from "@opencode/plugin/rpc";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
const window = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
label: z.string().nullable(),
|
||||||
|
seconds: z.number(),
|
||||||
|
used: z.number(),
|
||||||
|
resetsAt: z.number(),
|
||||||
|
remaining: z.number(),
|
||||||
|
sessionConsumed: z.number(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const QuotaRpc = Rpc.define({
|
||||||
|
id: "stanp-opencode.quota",
|
||||||
|
methods: {
|
||||||
|
status: {
|
||||||
|
input: z.object({ sessionID: z.string() }),
|
||||||
|
output: z
|
||||||
|
.object({ plan: z.string(), fetchedAt: z.number(), windows: z.array(window) })
|
||||||
|
.nullable(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
events: { updated: { schema: z.object({}) } },
|
||||||
|
});
|
||||||
+494
@@ -0,0 +1,494 @@
|
|||||||
|
import type { Plugin } from "@opencode/plugin";
|
||||||
|
import type { Credential } from "@opencode/schema/credential";
|
||||||
|
import type { Schema } from "effect";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
const INTEGRATION_ID = "openai";
|
||||||
|
const USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
|
||||||
|
const POLL_MS = 60_000;
|
||||||
|
const TIMEOUT_MS = 5_000;
|
||||||
|
const STORAGE_KEY = "chatgpt-quota";
|
||||||
|
|
||||||
|
function compactLimitIdentity(value: string) {
|
||||||
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSparkLimit(meteredFeature?: string, limitName?: string | null) {
|
||||||
|
return (
|
||||||
|
(meteredFeature !== undefined &&
|
||||||
|
compactLimitIdentity(meteredFeature) === "codexbengalfox") ||
|
||||||
|
(limitName != null && compactLimitIdentity(limitName) === "gpt53codexspark")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isReserveLimit(meteredFeature?: string, limitName?: string | null) {
|
||||||
|
const hasReserveToken = (value: string) => /(^|[^a-z0-9])reserve($|[^a-z0-9])/i.test(value);
|
||||||
|
return (
|
||||||
|
(meteredFeature !== undefined && hasReserveToken(meteredFeature)) ||
|
||||||
|
(limitName != null && hasReserveToken(limitName))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isExcludedLimit(meteredFeature?: string, limitName?: string | null) {
|
||||||
|
return isSparkLimit(meteredFeature, limitName) || isReserveLimit(meteredFeature, limitName);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isExcludedWindow(window: Pick<QuotaWindow, "id" | "label">) {
|
||||||
|
return isExcludedLimit(window.id.split(":", 1)[0], window.label);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface QuotaWindow {
|
||||||
|
id: string;
|
||||||
|
label: string | null;
|
||||||
|
seconds: number;
|
||||||
|
used: number;
|
||||||
|
resetsAt: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface QuotaSnapshot {
|
||||||
|
plan: string;
|
||||||
|
fetchedAt: number;
|
||||||
|
windows: QuotaWindow[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface QuotaStatus {
|
||||||
|
plan: string;
|
||||||
|
fetchedAt: number;
|
||||||
|
windows: Array<QuotaWindow & { remaining: number; sessionConsumed: number }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storedState = z.object({
|
||||||
|
account: z.string(),
|
||||||
|
latest: z
|
||||||
|
.object({
|
||||||
|
plan: z.string(),
|
||||||
|
fetchedAt: z.number(),
|
||||||
|
windows: z.array(
|
||||||
|
z.object({
|
||||||
|
id: z.string(),
|
||||||
|
label: z.string().nullable(),
|
||||||
|
seconds: z.number(),
|
||||||
|
used: z.number(),
|
||||||
|
resetsAt: z.number(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
sessions: z.record(
|
||||||
|
z.string(),
|
||||||
|
z.record(
|
||||||
|
z.string(),
|
||||||
|
z.object({ resetsAt: z.number(), lastUsed: z.number(), consumed: z.number() }),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
type StoredState = z.infer<typeof storedState>;
|
||||||
|
|
||||||
|
function withoutExcludedState(state: StoredState): StoredState {
|
||||||
|
const windows = state.latest?.windows.filter((window) => !isExcludedWindow(window));
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
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 QuotaFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
||||||
|
|
||||||
|
const quotaWindow = z.object({
|
||||||
|
limit_window_seconds: z.number().finite().positive(),
|
||||||
|
used_percent: z.number().finite(),
|
||||||
|
reset_at: z.number().finite(),
|
||||||
|
});
|
||||||
|
const additionalRateLimitIdentity = z.object({
|
||||||
|
limit_name: z.string().optional(),
|
||||||
|
metered_feature: z.string().optional(),
|
||||||
|
});
|
||||||
|
const quotaPayload = z.object({
|
||||||
|
plan_type: z.string(),
|
||||||
|
account_id: z.string().optional(),
|
||||||
|
rate_limit: z
|
||||||
|
.object({
|
||||||
|
allowed: z.boolean().optional(),
|
||||||
|
primary_window: quotaWindow.nullish(),
|
||||||
|
secondary_window: quotaWindow.nullish(),
|
||||||
|
})
|
||||||
|
.nullish(),
|
||||||
|
additional_rate_limits: z.preprocess(
|
||||||
|
(value) =>
|
||||||
|
Array.isArray(value)
|
||||||
|
? value.filter((item) => {
|
||||||
|
const identity = additionalRateLimitIdentity.safeParse(item);
|
||||||
|
return (
|
||||||
|
!identity.success ||
|
||||||
|
!isExcludedLimit(identity.data.metered_feature, identity.data.limit_name)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: value,
|
||||||
|
z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
limit_name: z.string(),
|
||||||
|
metered_feature: z.string(),
|
||||||
|
rate_limit: z
|
||||||
|
.object({
|
||||||
|
allowed: z.boolean().optional(),
|
||||||
|
primary_window: quotaWindow.nullish(),
|
||||||
|
secondary_window: quotaWindow.nullish(),
|
||||||
|
})
|
||||||
|
.nullish(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.nullish(),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
function normalizeWindow(
|
||||||
|
id: string,
|
||||||
|
item: z.infer<typeof quotaWindow>,
|
||||||
|
label?: string,
|
||||||
|
): QuotaWindow {
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
label: label ?? null,
|
||||||
|
seconds: item.limit_window_seconds,
|
||||||
|
used: Math.max(0, Math.min(100, item.used_percent)),
|
||||||
|
resetsAt: item.reset_at < 10_000_000_000 ? item.reset_at * 1000 : item.reset_at,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Normalize valid windows from the documented Codex usage payload. */
|
||||||
|
export function normalizeQuota(
|
||||||
|
input: Schema.Json,
|
||||||
|
fetchedAt = Date.now(),
|
||||||
|
): QuotaSnapshot | undefined {
|
||||||
|
const parsed = quotaPayload.safeParse(input);
|
||||||
|
if (!parsed.success) return;
|
||||||
|
const plan = parsed.data.plan_type.toLowerCase();
|
||||||
|
const windows: QuotaWindow[] = [];
|
||||||
|
if (parsed.data.rate_limit)
|
||||||
|
for (const [position, window] of [
|
||||||
|
["primary", parsed.data.rate_limit.primary_window],
|
||||||
|
["secondary", parsed.data.rate_limit.secondary_window],
|
||||||
|
] as const)
|
||||||
|
if (window) windows.push(normalizeWindow(`codex:${position}`, window));
|
||||||
|
for (const additional of parsed.data.additional_rate_limits ?? []) {
|
||||||
|
if (!additional.rate_limit) continue;
|
||||||
|
for (const [position, window] of [
|
||||||
|
["primary", additional.rate_limit.primary_window],
|
||||||
|
["secondary", additional.rate_limit.secondary_window],
|
||||||
|
] as const)
|
||||||
|
if (window)
|
||||||
|
windows.push(
|
||||||
|
normalizeWindow(
|
||||||
|
`${additional.metered_feature}:${position}`,
|
||||||
|
window,
|
||||||
|
additional.limit_name,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (windows.length === 0) return;
|
||||||
|
return { plan, fetchedAt, windows };
|
||||||
|
}
|
||||||
|
|
||||||
|
function accountID(credential: Credential.OAuth) {
|
||||||
|
const metadataID = z
|
||||||
|
.string()
|
||||||
|
.safeParse(credential.metadata?.accountID ?? credential.metadata?.accountId);
|
||||||
|
if (metadataID.success) return metadataID.data;
|
||||||
|
const parts = credential.access.split(".");
|
||||||
|
if (parts.length !== 3) return;
|
||||||
|
try {
|
||||||
|
const claims = z
|
||||||
|
.object({
|
||||||
|
chatgpt_account_id: z.string().optional(),
|
||||||
|
"https://api.openai.com/auth": z
|
||||||
|
.object({ chatgpt_account_id: z.string().optional() })
|
||||||
|
.optional(),
|
||||||
|
organizations: z.array(z.object({ id: z.string() })).optional(),
|
||||||
|
})
|
||||||
|
.safeParse(JSON.parse(Buffer.from(parts[1]!, "base64url").toString()));
|
||||||
|
if (!claims.success) return;
|
||||||
|
return (
|
||||||
|
claims.data.chatgpt_account_id ??
|
||||||
|
claims.data["https://api.openai.com/auth"]?.chatgpt_account_id ??
|
||||||
|
claims.data.organizations?.[0]?.id
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fingerprint(value: string) {
|
||||||
|
const bytes = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
|
||||||
|
return Buffer.from(bytes).toString("hex");
|
||||||
|
}
|
||||||
|
|
||||||
|
export class QuotaTracker {
|
||||||
|
private state: StoredState | undefined;
|
||||||
|
private timer: ReturnType<typeof setInterval> | undefined;
|
||||||
|
private request: Promise<QuotaSnapshot | undefined> | undefined;
|
||||||
|
private readonly requests = new Set<Promise<QuotaSnapshot | undefined>>();
|
||||||
|
private readonly active = new Map<string, Set<string>>();
|
||||||
|
private controller: AbortController | undefined;
|
||||||
|
private generation = 0;
|
||||||
|
private disposed = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly context: QuotaContext,
|
||||||
|
private readonly changed: () => Promise<void>,
|
||||||
|
private readonly fetcher: QuotaFetch = fetch,
|
||||||
|
private readonly pollMs = POLL_MS,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
try {
|
||||||
|
await this.resolveCredential();
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async resolveCredential(generation = this.generation) {
|
||||||
|
const connection = await this.context.integration.connection.active(INTEGRATION_ID);
|
||||||
|
if (generation !== this.generation) return;
|
||||||
|
const credential = connection
|
||||||
|
? await this.context.integration.connection.resolve(connection)
|
||||||
|
: undefined;
|
||||||
|
if (generation !== this.generation) return;
|
||||||
|
if (credential?.type !== "oauth") {
|
||||||
|
if (this.state) await this.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const id = accountID(credential);
|
||||||
|
const account = id
|
||||||
|
? await fingerprint(`account:${id}`)
|
||||||
|
: (this.state?.account ?? (await fingerprint(`credential:${credential.refresh}`)));
|
||||||
|
if (generation !== this.generation) return;
|
||||||
|
if (this.state?.account !== account) {
|
||||||
|
const parsed = storedState.safeParse(await this.context.storage.get(STORAGE_KEY));
|
||||||
|
if (generation !== this.generation) return;
|
||||||
|
const stored = parsed.success ? parsed.data : undefined;
|
||||||
|
if (generation !== this.generation) return;
|
||||||
|
this.state =
|
||||||
|
stored?.account === account
|
||||||
|
? withoutExcludedState(stored)
|
||||||
|
: { account, sessions: {} };
|
||||||
|
}
|
||||||
|
if (generation !== this.generation) return;
|
||||||
|
if (!this.timer) this.timer = setInterval(() => void this.refresh(), this.pollMs);
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async clear() {
|
||||||
|
this.state = undefined;
|
||||||
|
if (this.timer) clearInterval(this.timer);
|
||||||
|
this.timer = undefined;
|
||||||
|
await this.context.storage.remove(STORAGE_KEY);
|
||||||
|
await this.changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
async refresh(): Promise<QuotaSnapshot | undefined> {
|
||||||
|
const generation = this.generation;
|
||||||
|
if (this.disposed) return;
|
||||||
|
if (this.request) return this.request;
|
||||||
|
const request = this.query();
|
||||||
|
this.request = request;
|
||||||
|
this.requests.add(request);
|
||||||
|
try {
|
||||||
|
const result = await request;
|
||||||
|
if (generation !== this.generation) return;
|
||||||
|
return result ?? this.state?.latest;
|
||||||
|
} finally {
|
||||||
|
this.requests.delete(request);
|
||||||
|
if (this.request === request) this.request = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async query() {
|
||||||
|
const generation = this.generation;
|
||||||
|
try {
|
||||||
|
const credential = await this.resolveCredential(generation);
|
||||||
|
if (!credential || !this.state || generation !== this.generation) return;
|
||||||
|
const controller = new AbortController();
|
||||||
|
this.controller = controller;
|
||||||
|
const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
||||||
|
let response: Response;
|
||||||
|
try {
|
||||||
|
const headers = new Headers({
|
||||||
|
Authorization: `Bearer ${credential.access}`,
|
||||||
|
Accept: "application/json",
|
||||||
|
});
|
||||||
|
const id = accountID(credential);
|
||||||
|
if (id) headers.set("ChatGPT-Account-Id", id);
|
||||||
|
response = await this.fetcher(USAGE_URL, { headers, signal: controller.signal });
|
||||||
|
} finally {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
if (this.controller === controller) this.controller = undefined;
|
||||||
|
}
|
||||||
|
if (!response.ok || generation !== this.generation) return;
|
||||||
|
// SAFETY: JSON.parse semantics from Response.json produce only JSON values;
|
||||||
|
// quotaPayload validates all fields used below.
|
||||||
|
const payload = (await response.json()) as Schema.Json;
|
||||||
|
if (generation !== this.generation || !this.state) return;
|
||||||
|
const parsed = quotaPayload.safeParse(payload);
|
||||||
|
if (parsed.success && parsed.data.account_id) {
|
||||||
|
const account = await fingerprint(`account:${parsed.data.account_id}`);
|
||||||
|
if (generation !== this.generation || !this.state) return;
|
||||||
|
if (account !== this.state.account) this.state = { account, sessions: {} };
|
||||||
|
}
|
||||||
|
const snapshot = normalizeQuota(payload);
|
||||||
|
if (!snapshot) return;
|
||||||
|
this.apply(snapshot);
|
||||||
|
await this.persist();
|
||||||
|
await this.changed();
|
||||||
|
return snapshot;
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private apply(snapshot: QuotaSnapshot) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
const generation = this.generation;
|
||||||
|
try {
|
||||||
|
const root = await this.root(sessionID);
|
||||||
|
if (generation !== this.generation) return;
|
||||||
|
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) {
|
||||||
|
try {
|
||||||
|
const root = await this.root(sessionID);
|
||||||
|
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> {
|
||||||
|
if (!this.state?.latest) return;
|
||||||
|
const tracked = this.state.sessions[await this.root(sessionID)];
|
||||||
|
return {
|
||||||
|
plan: this.state.latest.plan,
|
||||||
|
fetchedAt: this.state.latest.fetchedAt,
|
||||||
|
windows: this.state.latest.windows.map((window) => ({
|
||||||
|
...window,
|
||||||
|
remaining: Math.max(0, 100 - window.used),
|
||||||
|
sessionConsumed: tracked?.[window.id]?.consumed ?? 0,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async persist() {
|
||||||
|
if (!this.state) return;
|
||||||
|
const value: Schema.Json = this.state.latest
|
||||||
|
? {
|
||||||
|
account: this.state.account,
|
||||||
|
sessions: this.state.sessions,
|
||||||
|
latest: this.state.latest,
|
||||||
|
}
|
||||||
|
: { account: this.state.account, sessions: this.state.sessions };
|
||||||
|
await this.context.storage.set(STORAGE_KEY, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
async authChanged(switched = false) {
|
||||||
|
if (switched) {
|
||||||
|
this.generation++;
|
||||||
|
this.controller?.abort();
|
||||||
|
this.controller = undefined;
|
||||||
|
this.request = undefined;
|
||||||
|
if (this.state) await this.clear();
|
||||||
|
}
|
||||||
|
await this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
async dispose() {
|
||||||
|
this.disposed = true;
|
||||||
|
this.generation++;
|
||||||
|
this.controller?.abort();
|
||||||
|
if (this.timer) clearInterval(this.timer);
|
||||||
|
this.timer = undefined;
|
||||||
|
await Promise.all(this.requests);
|
||||||
|
}
|
||||||
|
}
|
||||||
+78
@@ -0,0 +1,78 @@
|
|||||||
|
import { Plugin } from "@opencode/plugin/tui";
|
||||||
|
import { createResource, createSignal, For, Show } from "solid-js";
|
||||||
|
import type { QuotaStatus, QuotaWindow } from "./quota.js";
|
||||||
|
import { QuotaRpc } from "./quota-rpc.js";
|
||||||
|
|
||||||
|
function duration(seconds: number) {
|
||||||
|
if (seconds % 86_400 === 0) return `${seconds / 86_400}d`;
|
||||||
|
if (seconds % 3_600 === 0) return `${seconds / 3_600}h`;
|
||||||
|
return `${Math.round(seconds / 60)}m`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function percent(value: number) {
|
||||||
|
return value < 0.1 && value > 0 ? "<0.1" : value.toFixed(value < 10 ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatQuotaWindow(
|
||||||
|
window: QuotaWindow & { remaining: number; sessionConsumed: number },
|
||||||
|
) {
|
||||||
|
const label = window.label
|
||||||
|
? `${window.label} ${duration(window.seconds)}`
|
||||||
|
: duration(window.seconds);
|
||||||
|
return `${label}: ${percent(window.remaining)}% left · ~${percent(window.sessionConsumed)}pp this session`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadQuotaStatus(load: () => Promise<QuotaStatus | null>) {
|
||||||
|
try {
|
||||||
|
return await load();
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Plugin.define({
|
||||||
|
id: "stanp-opencode.quota-tui",
|
||||||
|
setup(context) {
|
||||||
|
const quota = context.client.rpc(QuotaRpc);
|
||||||
|
const [revision, setRevision] = createSignal(0);
|
||||||
|
const retry = setInterval(() => {
|
||||||
|
setRevision((value) => value + 1);
|
||||||
|
}, 60_000);
|
||||||
|
const unsubscribe = quota.events.on("updated", () => {
|
||||||
|
setRevision((value) => value + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
const Slot = (props: { sessionID: string }) => {
|
||||||
|
const [status] = createResource(
|
||||||
|
() => `${props.sessionID}:${revision()}`,
|
||||||
|
() => loadQuotaStatus(() => quota.status({ sessionID: props.sessionID })),
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<Show when={status()}>
|
||||||
|
<box flexDirection="column">
|
||||||
|
<text fg={context.theme.text.default}>
|
||||||
|
<b>ChatGPT quota ({status()!.plan})</b>
|
||||||
|
</text>
|
||||||
|
<For each={status()!.windows}>
|
||||||
|
{(window) => (
|
||||||
|
<text fg={context.theme.text.muted}>
|
||||||
|
{formatQuotaWindow(window)}
|
||||||
|
</text>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</box>
|
||||||
|
</Show>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const remove = context.ui.slot({
|
||||||
|
append: "sidebar.footer",
|
||||||
|
render: (input) => <Slot sessionID={input.sessionID} />,
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
remove();
|
||||||
|
unsubscribe();
|
||||||
|
clearInterval(retry);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
import { afterEach, expect, test } from "bun:test";
|
||||||
|
import { chmod, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const installer = fileURLToPath(new URL("../install-local.sh", import.meta.url));
|
||||||
|
const directories: string[] = [];
|
||||||
|
const jsonc = '{\n // This file must remain untouched.\n "theme": "dark"\n}\n';
|
||||||
|
const oldPlugin = 'export default { id: "old", setup() { return "old"; } };\n';
|
||||||
|
type FixtureConfig =
|
||||||
|
| { permissions: { shell: string }; plugins: { package: string }[] }
|
||||||
|
| {
|
||||||
|
theme: string;
|
||||||
|
plugins: {
|
||||||
|
package: string;
|
||||||
|
options: { mode: string; coordinate: string; lunaPriority: boolean };
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
| { plugins: string };
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await Promise.all(
|
||||||
|
directories.splice(0).map((path) => rm(path, { recursive: true, force: true })),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
async function run(command: string[], cwd: string, env: NodeJS.ProcessEnv) {
|
||||||
|
const child = Bun.spawn(command, {
|
||||||
|
cwd,
|
||||||
|
env,
|
||||||
|
stdout: "pipe",
|
||||||
|
stderr: "pipe",
|
||||||
|
timeout: 20_000,
|
||||||
|
});
|
||||||
|
const [exitCode, stdout, stderr] = await Promise.all([
|
||||||
|
child.exited,
|
||||||
|
new Response(child.stdout).text(),
|
||||||
|
new Response(child.stderr).text(),
|
||||||
|
]);
|
||||||
|
return { exitCode, stdout, stderr };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fixture(configValue?: FixtureConfig) {
|
||||||
|
const directory = await mkdtemp(join(tmpdir(), "stanp-local-install-"));
|
||||||
|
directories.push(directory);
|
||||||
|
const checkout = join(directory, "checkout with spaces");
|
||||||
|
const cwd = join(directory, "different cwd");
|
||||||
|
const config = join(directory, "config with spaces");
|
||||||
|
const bin = join(directory, "bin");
|
||||||
|
const installed = join(config, "plugins", "stanp-opencode");
|
||||||
|
await Promise.all([
|
||||||
|
mkdir(checkout),
|
||||||
|
mkdir(cwd),
|
||||||
|
mkdir(bin),
|
||||||
|
mkdir(installed, { recursive: true }),
|
||||||
|
]);
|
||||||
|
await Promise.all([
|
||||||
|
Bun.write(join(checkout, "install-local.sh"), Bun.file(installer)),
|
||||||
|
writeFile(
|
||||||
|
join(checkout, "package.json"),
|
||||||
|
JSON.stringify({
|
||||||
|
name: "stanp-opencode",
|
||||||
|
version: "1.0.0",
|
||||||
|
type: "module",
|
||||||
|
exports: { ".": "./dist/index.js", "./tui": { import: "./dist/tui.js" } },
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
writeFile(join(checkout, "bun.lock"), ""),
|
||||||
|
writeFile(join(config, "opencode.jsonc"), jsonc),
|
||||||
|
writeFile(
|
||||||
|
join(config, "opencode.json"),
|
||||||
|
JSON.stringify(
|
||||||
|
configValue ?? {
|
||||||
|
permissions: { shell: "ask" },
|
||||||
|
plugins: [{ package: "existing-plugin" }],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
writeFile(join(installed, "index.js"), oldPlugin),
|
||||||
|
writeFile(
|
||||||
|
join(installed, "package.json"),
|
||||||
|
'{"name":"stanp-opencode","type":"module","main":"./index.js"}\n',
|
||||||
|
),
|
||||||
|
writeFile(join(config, "plugins", "stanp-opencode.js"), "legacy\n"),
|
||||||
|
writeFile(
|
||||||
|
join(bin, "bun"),
|
||||||
|
`#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
if [[ "\${1:-}" == "install" ]]; then
|
||||||
|
[[ "\${2:-}" == "--frozen-lockfile" ]]
|
||||||
|
printf '%s\n' "$PWD" >> "$CALLS"
|
||||||
|
[[ "$MODE" != "dependency" ]]
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
if [[ "\${1:-}" == "run" && "\${2:-}" == "build" ]]; then
|
||||||
|
printf '%s\n' "$PWD" >> "$CALLS"
|
||||||
|
[[ "$MODE" != "build" ]]
|
||||||
|
mkdir -p dist
|
||||||
|
if [[ "$MODE" == "validation" ]]; then
|
||||||
|
printf '%s\n' 'export default { id: "stanp-opencode", server() {} };' > dist/index.js
|
||||||
|
else
|
||||||
|
printf 'export default { id: "stanp-opencode", setup() { return "%s"; } };\n' "$GENERATION" > dist/index.js
|
||||||
|
fi
|
||||||
|
printf '%s\n' 'export default { id: "stanp-opencode.quota-tui", setup() {} };' > dist/tui.js
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
exec "$REAL_BUN" "$@"
|
||||||
|
`,
|
||||||
|
),
|
||||||
|
writeFile(
|
||||||
|
join(bin, "curl"),
|
||||||
|
`#!/usr/bin/env bash
|
||||||
|
touch "$FETCH_MARKER"
|
||||||
|
printf 'release fetching is forbidden\n' >&2
|
||||||
|
exit 99
|
||||||
|
`,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
await Promise.all([chmod(join(bin, "bun"), 0o755), chmod(join(bin, "curl"), 0o755)]);
|
||||||
|
const env = {
|
||||||
|
...Bun.env,
|
||||||
|
PATH: `${bin}:${dirname(process.execPath)}:${Bun.env.PATH ?? "/usr/bin:/bin"}`,
|
||||||
|
HOME: join(directory, "home"),
|
||||||
|
XDG_CONFIG_HOME: join(directory, "ignored-xdg"),
|
||||||
|
OPENCODE_CONFIG_DIR: config,
|
||||||
|
REAL_BUN: process.execPath,
|
||||||
|
MODE: "success",
|
||||||
|
GENERATION: "first",
|
||||||
|
CALLS: join(directory, "calls"),
|
||||||
|
FETCH_MARKER: join(directory, "release-fetch-attempted"),
|
||||||
|
};
|
||||||
|
return { directory, checkout, cwd, config, installed, env };
|
||||||
|
}
|
||||||
|
|
||||||
|
test("builds from its checkout and installs defaults when invoked elsewhere", async () => {
|
||||||
|
const setup = await fixture();
|
||||||
|
const result = await run(
|
||||||
|
["bash", join(setup.checkout, "install-local.sh")],
|
||||||
|
setup.cwd,
|
||||||
|
setup.env,
|
||||||
|
);
|
||||||
|
expect(result, result.stderr).toMatchObject({ exitCode: 0 });
|
||||||
|
expect(await readFile(setup.env.CALLS, "utf8")).toBe(`${setup.checkout}\n${setup.checkout}\n`);
|
||||||
|
expect(await Bun.file(setup.env.FETCH_MARKER).exists()).toBe(false);
|
||||||
|
expect(await readFile(join(setup.config, "opencode.jsonc"), "utf8")).toBe(jsonc);
|
||||||
|
expect(JSON.parse(await readFile(join(setup.config, "opencode.json"), "utf8"))).toEqual({
|
||||||
|
$schema: "https://opencode.ai/config.json",
|
||||||
|
permissions: { shell: "ask" },
|
||||||
|
plugins: [
|
||||||
|
{ package: "existing-plugin" },
|
||||||
|
{
|
||||||
|
package: "./plugins/stanp-opencode",
|
||||||
|
options: { mode: "gpt", provider: "openai", lunaPriority: true },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const imported = await run(
|
||||||
|
[
|
||||||
|
process.execPath,
|
||||||
|
"-e",
|
||||||
|
"const { default: plugin } = await import(process.argv[1]); console.log(plugin.setup());",
|
||||||
|
setup.installed,
|
||||||
|
],
|
||||||
|
setup.cwd,
|
||||||
|
setup.env,
|
||||||
|
);
|
||||||
|
expect(imported, imported.stderr).toMatchObject({ exitCode: 0, stdout: "first\n" });
|
||||||
|
expect((await readdir(setup.installed)).sort()).toEqual(["index.js", "package.json", "tui.js"]);
|
||||||
|
expect(await Bun.file(join(setup.config, "plugins", "stanp-opencode.js")).exists()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("reinstall replaces bundles while preserving existing settings and plugin options", async () => {
|
||||||
|
const configured = {
|
||||||
|
theme: "dark",
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
package: "./plugins/stanp-opencode",
|
||||||
|
options: { mode: "custom", coordinate: "provider/model", lunaPriority: false },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const setup = await fixture(configured);
|
||||||
|
const first = await run(
|
||||||
|
["bash", join(setup.checkout, "install-local.sh")],
|
||||||
|
setup.cwd,
|
||||||
|
setup.env,
|
||||||
|
);
|
||||||
|
expect(first, first.stderr).toMatchObject({ exitCode: 0 });
|
||||||
|
const second = await run(["bash", join(setup.checkout, "install-local.sh")], setup.cwd, {
|
||||||
|
...setup.env,
|
||||||
|
GENERATION: "second",
|
||||||
|
});
|
||||||
|
expect(second, second.stderr).toMatchObject({ exitCode: 0 });
|
||||||
|
expect(JSON.parse(await readFile(join(setup.config, "opencode.json"), "utf8"))).toEqual({
|
||||||
|
$schema: "https://opencode.ai/config.json",
|
||||||
|
...configured,
|
||||||
|
});
|
||||||
|
expect(await readFile(join(setup.installed, "index.js"), "utf8")).toContain('return "second"');
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const mode of ["dependency", "build", "validation", "config"] as const) {
|
||||||
|
test(`${mode} failure leaves the previous installation and configuration untouched`, async () => {
|
||||||
|
const invalidConfig = mode === "config" ? { plugins: "not-an-array" } : undefined;
|
||||||
|
const setup = await fixture(invalidConfig);
|
||||||
|
const beforeConfig = await readFile(join(setup.config, "opencode.json"), "utf8");
|
||||||
|
const result = await run(["bash", join(setup.checkout, "install-local.sh")], setup.cwd, {
|
||||||
|
...setup.env,
|
||||||
|
MODE: mode === "config" ? "success" : mode,
|
||||||
|
});
|
||||||
|
expect(result.exitCode, result.stderr).not.toBe(0);
|
||||||
|
expect(await readFile(join(setup.installed, "index.js"), "utf8")).toBe(oldPlugin);
|
||||||
|
expect(await readFile(join(setup.config, "opencode.json"), "utf8")).toBe(beforeConfig);
|
||||||
|
expect(await readFile(join(setup.config, "opencode.jsonc"), "utf8")).toBe(jsonc);
|
||||||
|
expect(await readFile(join(setup.config, "plugins", "stanp-opencode.js"), "utf8")).toBe(
|
||||||
|
"legacy\n",
|
||||||
|
);
|
||||||
|
expect((await readdir(join(setup.config, "plugins"))).sort()).toEqual([
|
||||||
|
"stanp-opencode",
|
||||||
|
"stanp-opencode.js",
|
||||||
|
]);
|
||||||
|
expect(await Bun.file(setup.env.FETCH_MARKER).exists()).toBe(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -96,7 +96,7 @@ async function install(mode: "native" | "checksum" | "legacy", configured = fals
|
|||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
type: "module",
|
type: "module",
|
||||||
main: "./dist/index.js",
|
main: "./dist/index.js",
|
||||||
exports: "./dist/index.js",
|
exports: { ".": "./dist/index.js", "./tui": "./dist/tui.js" },
|
||||||
scripts: { postinstall: "bun ./postinstall.js" },
|
scripts: { postinstall: "bun ./postinstall.js" },
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@@ -111,6 +111,10 @@ async function install(mode: "native" | "checksum" | "legacy", configured = fals
|
|||||||
? 'export default { id: "stanp-opencode", async server() { return {}; } };\n'
|
? 'export default { id: "stanp-opencode", async server() { return {}; } };\n'
|
||||||
: 'export default { id: "stanp-opencode", setup() { return "native-ready"; } };\n'),
|
: 'export default { id: "stanp-opencode", setup() { return "native-ready"; } };\n'),
|
||||||
),
|
),
|
||||||
|
writeFile(
|
||||||
|
join(fixture, "dist", "tui.js"),
|
||||||
|
'export default { id: "stanp-opencode.quota-tui", setup() { return "tui-ready"; } };\n',
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
const env = {
|
const env = {
|
||||||
...Bun.env,
|
...Bun.env,
|
||||||
@@ -220,6 +224,7 @@ test("installs an importable native plugin and default config under XDG without
|
|||||||
expect(await Bun.file(join(config, "plugins", "stanp-opencode", "package.json")).exists()).toBe(
|
expect(await Bun.file(join(config, "plugins", "stanp-opencode", "package.json")).exists()).toBe(
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
expect(await Bun.file(join(config, "plugins", "stanp-opencode", "tui.js")).exists()).toBe(true);
|
||||||
expect(
|
expect(
|
||||||
await readFile(join(config, "stanp-opencode", "install.previous", "index.js"), "utf8"),
|
await readFile(join(config, "stanp-opencode", "install.previous", "index.js"), "utf8"),
|
||||||
).toBe(previousPlugin);
|
).toBe(previousPlugin);
|
||||||
|
|||||||
+50
-6
@@ -38,7 +38,7 @@ async function host(
|
|||||||
build.permissions.push({ action: "shell", resource: "git push *", effect: "ask" });
|
build.permissions.push({ action: "shell", resource: "git push *", effect: "ask" });
|
||||||
agents.set("build", build);
|
agents.set("build", build);
|
||||||
const originalBuild = structuredClone(build);
|
const originalBuild = structuredClone(build);
|
||||||
const sessionHooks: Record<string, (event: HookEvent) => Promise<void> | void> = {};
|
const sessionHooks: Record<string, ((event: HookEvent) => Promise<void> | void)[]> = {};
|
||||||
let before!: (event: { tool: string; agent: string; input: unknown }) => Promise<void> | void;
|
let before!: (event: { tool: string; agent: string; input: unknown }) => Promise<void> | void;
|
||||||
let parent = "build";
|
let parent = "build";
|
||||||
let child = "fast-lo";
|
let child = "fast-lo";
|
||||||
@@ -46,8 +46,14 @@ async function host(
|
|||||||
const registration = { async dispose() {} };
|
const registration = { async dispose() {} };
|
||||||
let transform!: (editor: AgentEditor) => void;
|
let transform!: (editor: AgentEditor) => void;
|
||||||
let reloaded = Promise.withResolvers<void>();
|
let reloaded = Promise.withResolvers<void>();
|
||||||
let events!: ReadableStreamDefaultController<{ type: string }>;
|
let events!: ReadableStreamDefaultController<{
|
||||||
const stream = new ReadableStream<{ type: string }>({
|
type: string;
|
||||||
|
location?: { directory: string; workspaceID?: string };
|
||||||
|
}>;
|
||||||
|
const stream = new ReadableStream<{
|
||||||
|
type: string;
|
||||||
|
location?: { directory: string; workspaceID?: string };
|
||||||
|
}>({
|
||||||
start(controller) {
|
start(controller) {
|
||||||
events = controller;
|
events = controller;
|
||||||
},
|
},
|
||||||
@@ -101,6 +107,7 @@ 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: "/test" },
|
||||||
options,
|
options,
|
||||||
catalog: {
|
catalog: {
|
||||||
model: {
|
model: {
|
||||||
@@ -122,6 +129,24 @@ async function host(
|
|||||||
async set(key: string, value: JsonValue) {
|
async set(key: string, value: JsonValue) {
|
||||||
storage.set(key, value);
|
storage.set(key, value);
|
||||||
},
|
},
|
||||||
|
async remove(key: string) {
|
||||||
|
storage.delete(key);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
integration: {
|
||||||
|
connection: {
|
||||||
|
async active() {
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
async resolve() {
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rpc: {
|
||||||
|
async register() {
|
||||||
|
return { ...registration, events: { async emit() {} } };
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mcp: {
|
mcp: {
|
||||||
async transform(callback: typeof mcpTransform) {
|
async transform(callback: typeof mcpTransform) {
|
||||||
@@ -165,7 +190,7 @@ async function host(
|
|||||||
},
|
},
|
||||||
session: {
|
session: {
|
||||||
async hook(name: string, callback: (event: HookEvent) => Promise<void> | void) {
|
async hook(name: string, callback: (event: HookEvent) => Promise<void> | void) {
|
||||||
sessionHooks[name] = callback;
|
(sessionHooks[name] ??= []).push(callback);
|
||||||
return registration;
|
return registration;
|
||||||
},
|
},
|
||||||
async get({ sessionID }: { sessionID: string }) {
|
async get({ sessionID }: { sessionID: string }) {
|
||||||
@@ -209,6 +234,10 @@ async function host(
|
|||||||
events.enqueue({ type: "agent.updated" });
|
events.enqueue({ type: "agent.updated" });
|
||||||
await reloaded.promise;
|
await reloaded.promise;
|
||||||
},
|
},
|
||||||
|
changeBuildPermissionsElsewhere(permissions: Agent.Info["permissions"]) {
|
||||||
|
build.permissions = [...permissions];
|
||||||
|
events.enqueue({ type: "agent.updated", location: { directory: "/other" } });
|
||||||
|
},
|
||||||
async changeCodegraph(
|
async changeCodegraph(
|
||||||
server:
|
server:
|
||||||
| { type: "local"; command: string[]; codemode?: boolean; disabled?: boolean }
|
| { type: "local"; command: string[]; codemode?: boolean; disabled?: boolean }
|
||||||
@@ -236,7 +265,7 @@ async function host(
|
|||||||
async command(caller: string, target: string) {
|
async command(caller: string, target: string) {
|
||||||
parent = caller;
|
parent = caller;
|
||||||
child = target;
|
child = target;
|
||||||
await sessionHooks.prompt!({ sessionID: "child" });
|
for (const hook of sessionHooks.prompt ?? []) await hook({ sessionID: "child" });
|
||||||
},
|
},
|
||||||
async tools(caller: string) {
|
async tools(caller: string) {
|
||||||
const event: ModelContext = {
|
const event: ModelContext = {
|
||||||
@@ -251,7 +280,7 @@ async function host(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
await sessionHooks.context!(event);
|
for (const hook of sessionHooks.context ?? []) await hook(event);
|
||||||
return event.tools;
|
return event.tools;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -459,6 +488,21 @@ test("late build permission overrides remain effective for workers and coordinat
|
|||||||
).toBe("deny");
|
).toBe("deny");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("events from another location do not reload this location's agents", async () => {
|
||||||
|
const result = await host();
|
||||||
|
result.changeBuildPermissionsElsewhere([
|
||||||
|
...result.build.permissions,
|
||||||
|
{ action: "read", resource: "*.env", effect: "deny" },
|
||||||
|
]);
|
||||||
|
await result.refresh(allModels);
|
||||||
|
expect(
|
||||||
|
result.agents
|
||||||
|
.get("coordinate")
|
||||||
|
?.permissions.filter((rule) => rule.action === "read" && rule.resource === "*.env")
|
||||||
|
.at(-1)?.effect,
|
||||||
|
).toBe("ask");
|
||||||
|
});
|
||||||
|
|
||||||
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" }];
|
||||||
|
|||||||
@@ -0,0 +1,548 @@
|
|||||||
|
import { expect, test } from "bun:test";
|
||||||
|
import type { Schema } from "effect";
|
||||||
|
import { normalizeQuota, QuotaTracker } from "../src/quota.js";
|
||||||
|
import { formatQuotaWindow, loadQuotaStatus } from "../src/tui.js";
|
||||||
|
|
||||||
|
const plus = {
|
||||||
|
plan_type: "plus",
|
||||||
|
account_id: "account-one",
|
||||||
|
rate_limit: {
|
||||||
|
allowed: true,
|
||||||
|
limit_reached: false,
|
||||||
|
primary_window: {
|
||||||
|
used_percent: 12.5,
|
||||||
|
limit_window_seconds: 18_000,
|
||||||
|
reset_after_seconds: 1_000,
|
||||||
|
reset_at: 2_000_000_000,
|
||||||
|
},
|
||||||
|
secondary_window: {
|
||||||
|
used_percent: 41,
|
||||||
|
limit_window_seconds: 604_800,
|
||||||
|
reset_after_seconds: 2_000,
|
||||||
|
reset_at: 2_000_500_000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
test("normalizes representative Plus and Pro payloads and hides absent windows", () => {
|
||||||
|
expect(normalizeQuota(plus, 123)).toEqual({
|
||||||
|
plan: "plus",
|
||||||
|
fetchedAt: 123,
|
||||||
|
windows: [
|
||||||
|
{
|
||||||
|
id: "codex:primary",
|
||||||
|
label: null,
|
||||||
|
seconds: 18_000,
|
||||||
|
used: 12.5,
|
||||||
|
resetsAt: 2_000_000_000_000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "codex:secondary",
|
||||||
|
label: null,
|
||||||
|
seconds: 604_800,
|
||||||
|
used: 41,
|
||||||
|
resetsAt: 2_000_500_000_000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(normalizeQuota({ ...plus, plan_type: "pro" }, 123)?.windows).toHaveLength(2);
|
||||||
|
expect(
|
||||||
|
normalizeQuota({
|
||||||
|
plan_type: "pro",
|
||||||
|
rate_limit: { primary_window: plus.rate_limit.primary_window },
|
||||||
|
})?.windows,
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
id: "codex:primary",
|
||||||
|
label: null,
|
||||||
|
seconds: 18_000,
|
||||||
|
used: 12.5,
|
||||||
|
resetsAt: 2_000_000_000_000,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
expect(normalizeQuota({ plan_type: "plus", rate_limit: null })).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("normalizes additional named limits with stable IDs distinct from equal durations", () => {
|
||||||
|
const normalized = normalizeQuota({
|
||||||
|
...plus,
|
||||||
|
additional_rate_limits: [
|
||||||
|
{
|
||||||
|
limit_name: "GPT-5.6 Luna",
|
||||||
|
metered_feature: "codex_luna",
|
||||||
|
rate_limit: { primary_window: plus.rate_limit.primary_window },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(normalized?.windows.map((window) => window.id)).toEqual([
|
||||||
|
"codex:primary",
|
||||||
|
"codex:secondary",
|
||||||
|
"codex_luna:primary",
|
||||||
|
]);
|
||||||
|
expect(normalized?.windows[2]?.label).toBe("GPT-5.6 Luna");
|
||||||
|
expect(
|
||||||
|
normalizeQuota({
|
||||||
|
plan_type: "pro",
|
||||||
|
rate_limit: null,
|
||||||
|
additional_rate_limits: [
|
||||||
|
{
|
||||||
|
limit_name: "GPT-5.6 Luna",
|
||||||
|
metered_feature: "codex_luna",
|
||||||
|
rate_limit: { primary_window: plus.rate_limit.primary_window },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})?.windows.map((window) => window.id),
|
||||||
|
).toEqual(["codex_luna:primary"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("ignores Spark and representative reserve limits while preserving other quotas", () => {
|
||||||
|
const normalized = normalizeQuota({
|
||||||
|
...plus,
|
||||||
|
additional_rate_limits: [
|
||||||
|
{
|
||||||
|
limit_name: "gpt 5_3 codex spark",
|
||||||
|
metered_feature: "CODEX-BENGALFOX",
|
||||||
|
rate_limit: {
|
||||||
|
primary_window: { used_percent: "invalid" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
limit_name: "Luna Reserve",
|
||||||
|
metered_feature: "codex_luna",
|
||||||
|
rate_limit: { primary_window: { used_percent: "invalid" } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
limit_name: "Luna overflow",
|
||||||
|
metered_feature: "codex_luna_reserve",
|
||||||
|
rate_limit: { primary_window: { used_percent: "invalid" } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
limit_name: "GPT-5.6 Luna",
|
||||||
|
metered_feature: "codex_luna",
|
||||||
|
rate_limit: { primary_window: plus.rate_limit.primary_window },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
limit_name: "Preserved capacity",
|
||||||
|
metered_feature: "codex_preserved",
|
||||||
|
rate_limit: { primary_window: plus.rate_limit.primary_window },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(normalized?.windows.map((window) => window.id)).toEqual([
|
||||||
|
"codex:primary",
|
||||||
|
"codex:secondary",
|
||||||
|
"codex_luna:primary",
|
||||||
|
"codex_preserved:primary",
|
||||||
|
]);
|
||||||
|
expect(normalized?.windows.slice(2).map((window) => window.label)).toEqual([
|
||||||
|
"GPT-5.6 Luna",
|
||||||
|
"Preserved capacity",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns no quota for a Spark-only payload", () => {
|
||||||
|
expect(
|
||||||
|
normalizeQuota({
|
||||||
|
plan_type: "pro",
|
||||||
|
additional_rate_limits: [
|
||||||
|
{
|
||||||
|
limit_name: "GPT-5.3-Codex-Spark",
|
||||||
|
metered_feature: "codex_bengalfox",
|
||||||
|
rate_limit: { primary_window: plus.rate_limit.primary_window },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
function fixture(
|
||||||
|
credential:
|
||||||
|
| {
|
||||||
|
type: "oauth";
|
||||||
|
access: string;
|
||||||
|
refresh: string;
|
||||||
|
metadata?: { accountID?: string; accountId?: string };
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "key";
|
||||||
|
key: string;
|
||||||
|
},
|
||||||
|
payloads: unknown[],
|
||||||
|
pollMs = 1_000_000,
|
||||||
|
storageReads: Promise<Schema.Json | undefined>[] = [],
|
||||||
|
) {
|
||||||
|
const stored = new Map<string, Schema.Json>();
|
||||||
|
const sessions = new Map([
|
||||||
|
["root", {}],
|
||||||
|
["child", { parentID: "root" }],
|
||||||
|
]);
|
||||||
|
let calls = 0;
|
||||||
|
let storageCalls = 0;
|
||||||
|
let changes = 0;
|
||||||
|
let current: typeof credential | undefined = credential;
|
||||||
|
const headers: Headers[] = [];
|
||||||
|
const tracker = new QuotaTracker(
|
||||||
|
// SAFETY: This focused fixture implements only the native calls exercised by
|
||||||
|
// QuotaTracker; branded connection and session fields are irrelevant here.
|
||||||
|
{
|
||||||
|
integration: {
|
||||||
|
connection: {
|
||||||
|
async active() {
|
||||||
|
// SAFETY: Only presence is observed; QuotaTracker passes this value back unchanged.
|
||||||
|
return current ? ({ id: "connection" } as never) : undefined;
|
||||||
|
},
|
||||||
|
async resolve() {
|
||||||
|
// SAFETY: The fixture covers the credential discriminant and fields QuotaTracker reads.
|
||||||
|
return current 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: {
|
||||||
|
async get(key: string) {
|
||||||
|
storageCalls++;
|
||||||
|
const deferred = storageReads.shift();
|
||||||
|
if (deferred) return deferred;
|
||||||
|
return stored.get(key);
|
||||||
|
},
|
||||||
|
async set(key: string, value: Schema.Json) {
|
||||||
|
stored.set(key, value);
|
||||||
|
},
|
||||||
|
async remove(key: string) {
|
||||||
|
stored.delete(key);
|
||||||
|
},
|
||||||
|
async scan() {
|
||||||
|
return { entries: [] };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
changes++;
|
||||||
|
},
|
||||||
|
async (_url, init) => {
|
||||||
|
calls++;
|
||||||
|
const requestHeaders = new Headers(init?.headers);
|
||||||
|
headers.push(requestHeaders);
|
||||||
|
expect(requestHeaders.get("authorization")).toStartWith("Bearer ");
|
||||||
|
const payload = await (payloads.shift() ?? plus);
|
||||||
|
if (payload instanceof Error) throw payload;
|
||||||
|
return Response.json(payload);
|
||||||
|
},
|
||||||
|
pollMs,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
tracker,
|
||||||
|
calls: () => calls,
|
||||||
|
storageCalls: () => storageCalls,
|
||||||
|
changes: () => changes,
|
||||||
|
headers,
|
||||||
|
switch(credential: typeof current) {
|
||||||
|
current = credential;
|
||||||
|
},
|
||||||
|
logout: () => {
|
||||||
|
current = undefined;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function accountFingerprint(id: string) {
|
||||||
|
const bytes = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(`account:${id}`));
|
||||||
|
return Buffer.from(bytes).toString("hex");
|
||||||
|
}
|
||||||
|
|
||||||
|
test("removes cached Spark and representative reserve windows and consumption while offline", async () => {
|
||||||
|
const cached = {
|
||||||
|
account: await accountFingerprint("account-one"),
|
||||||
|
latest: {
|
||||||
|
plan: "pro",
|
||||||
|
fetchedAt: 123,
|
||||||
|
windows: [
|
||||||
|
{
|
||||||
|
id: "codex:primary",
|
||||||
|
label: null,
|
||||||
|
seconds: 18_000,
|
||||||
|
used: 12.5,
|
||||||
|
resetsAt: 2_000_000_000_000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "CODEX-BENGALFOX:primary",
|
||||||
|
label: "GPT 5.3 Codex Spark",
|
||||||
|
seconds: 18_000,
|
||||||
|
used: 80,
|
||||||
|
resetsAt: 2_000_000_000_000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "codex_luna_reserve:primary",
|
||||||
|
label: "Luna Reserve",
|
||||||
|
seconds: 18_000,
|
||||||
|
used: 60,
|
||||||
|
resetsAt: 2_000_000_000_000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "codex_luna:primary",
|
||||||
|
label: "GPT-5.6 Luna",
|
||||||
|
seconds: 18_000,
|
||||||
|
used: 20,
|
||||||
|
resetsAt: 2_000_000_000_000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
sessions: {
|
||||||
|
root: {
|
||||||
|
"codex:primary": {
|
||||||
|
resetsAt: 2_000_000_000_000,
|
||||||
|
lastUsed: 12.5,
|
||||||
|
consumed: 2,
|
||||||
|
},
|
||||||
|
"CODEX-BENGALFOX:primary": {
|
||||||
|
resetsAt: 2_000_000_000_000,
|
||||||
|
lastUsed: 80,
|
||||||
|
consumed: 40,
|
||||||
|
},
|
||||||
|
"codex_luna_reserve:primary": {
|
||||||
|
resetsAt: 2_000_000_000_000,
|
||||||
|
lastUsed: 60,
|
||||||
|
consumed: 30,
|
||||||
|
},
|
||||||
|
"codex_luna:primary": {
|
||||||
|
resetsAt: 2_000_000_000_000,
|
||||||
|
lastUsed: 20,
|
||||||
|
consumed: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const result = fixture(
|
||||||
|
{
|
||||||
|
type: "oauth",
|
||||||
|
access: "opaque",
|
||||||
|
refresh: "refresh",
|
||||||
|
metadata: { accountID: "account-one" },
|
||||||
|
},
|
||||||
|
[new Error("offline")],
|
||||||
|
1_000_000,
|
||||||
|
[Promise.resolve(cached)],
|
||||||
|
);
|
||||||
|
|
||||||
|
await result.tracker.init();
|
||||||
|
const status = await result.tracker.status("root");
|
||||||
|
expect(status?.windows.map((window) => window.id)).toEqual([
|
||||||
|
"codex:primary",
|
||||||
|
"codex_luna:primary",
|
||||||
|
]);
|
||||||
|
expect(status?.windows[0]?.sessionConsumed).toBe(2);
|
||||||
|
expect(status?.windows[1]?.sessionConsumed).toBe(3);
|
||||||
|
await result.tracker.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("activates only for OAuth and establishes an awaited root baseline shared by children", async () => {
|
||||||
|
const key = fixture({ type: "key", key: "secret" }, [plus]);
|
||||||
|
await key.tracker.init();
|
||||||
|
await key.tracker.start("root");
|
||||||
|
expect(key.calls()).toBe(0);
|
||||||
|
expect(await key.tracker.status("root")).toBeUndefined();
|
||||||
|
await key.tracker.dispose();
|
||||||
|
|
||||||
|
const oauth = fixture(
|
||||||
|
{
|
||||||
|
type: "oauth",
|
||||||
|
access: "opaque",
|
||||||
|
refresh: "refresh",
|
||||||
|
metadata: { accountID: "account-one" },
|
||||||
|
},
|
||||||
|
[
|
||||||
|
plus,
|
||||||
|
{
|
||||||
|
...plus,
|
||||||
|
rate_limit: {
|
||||||
|
...plus.rate_limit,
|
||||||
|
primary_window: { ...plus.rate_limit.primary_window, used_percent: 17.5 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
await oauth.tracker.init();
|
||||||
|
await oauth.tracker.start("root");
|
||||||
|
expect(oauth.calls()).toBe(1);
|
||||||
|
expect(oauth.headers[0]?.get("chatgpt-account-id")).toBe("account-one");
|
||||||
|
await oauth.tracker.refresh();
|
||||||
|
const child = await oauth.tracker.status("child");
|
||||||
|
expect(child?.windows[0]?.sessionConsumed).toBe(5);
|
||||||
|
expect(child?.windows[0]?.remaining).toBe(82.5);
|
||||||
|
await oauth.tracker.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("polls, carries consumption across quota resets, tolerates errors, and clears on logout", async () => {
|
||||||
|
const reset = {
|
||||||
|
...plus,
|
||||||
|
rate_limit: {
|
||||||
|
...plus.rate_limit,
|
||||||
|
primary_window: {
|
||||||
|
...plus.rate_limit.primary_window,
|
||||||
|
used_percent: 2,
|
||||||
|
reset_at: 2_000_100_000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const result = fixture(
|
||||||
|
{
|
||||||
|
type: "oauth",
|
||||||
|
access: "opaque",
|
||||||
|
refresh: "refresh",
|
||||||
|
metadata: { accountID: "account-one" },
|
||||||
|
},
|
||||||
|
[plus, new Error("offline"), reset, reset, reset, reset],
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
await result.tracker.init();
|
||||||
|
await result.tracker.start("root");
|
||||||
|
await Bun.sleep(35);
|
||||||
|
const status = await result.tracker.status("root");
|
||||||
|
expect(result.calls()).toBeGreaterThanOrEqual(3);
|
||||||
|
expect(status?.windows[0]?.sessionConsumed).toBe(2);
|
||||||
|
result.logout();
|
||||||
|
await result.tracker.authChanged(true);
|
||||||
|
expect(await result.tracker.status("root")).toBeUndefined();
|
||||||
|
const calls = result.calls();
|
||||||
|
await result.tracker.dispose();
|
||||||
|
await Bun.sleep(20);
|
||||||
|
expect(result.calls()).toBe(calls);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("sidebar text places estimated percentage-point use beside latest remaining quota", () => {
|
||||||
|
expect(
|
||||||
|
formatQuotaWindow({
|
||||||
|
seconds: 604_800,
|
||||||
|
id: "codex:secondary",
|
||||||
|
label: null,
|
||||||
|
used: 25,
|
||||||
|
remaining: 75,
|
||||||
|
sessionConsumed: 2.25,
|
||||||
|
resetsAt: 0,
|
||||||
|
}),
|
||||||
|
).toBe("7d: 75% left · ~2.3pp this session");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("inactive roots freeze, resume from a cached baseline on failure, and deactivate by family", async () => {
|
||||||
|
const used = (percent: number) => ({
|
||||||
|
...plus,
|
||||||
|
rate_limit: {
|
||||||
|
...plus.rate_limit,
|
||||||
|
primary_window: { ...plus.rate_limit.primary_window, used_percent: percent },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const result = fixture(
|
||||||
|
{
|
||||||
|
type: "oauth",
|
||||||
|
access: "opaque",
|
||||||
|
refresh: "refresh",
|
||||||
|
metadata: { accountID: "account-one" },
|
||||||
|
},
|
||||||
|
[used(10), used(11), used(30), new Error("temporary"), used(30), used(33), used(35)],
|
||||||
|
);
|
||||||
|
await result.tracker.init();
|
||||||
|
await result.tracker.start("root");
|
||||||
|
await result.tracker.complete("root");
|
||||||
|
expect((await result.tracker.status("root"))?.windows[0]?.sessionConsumed).toBe(1);
|
||||||
|
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.refresh();
|
||||||
|
await result.tracker.complete("child");
|
||||||
|
expect((await result.tracker.status("root"))?.windows[0]?.sessionConsumed).toBe(6);
|
||||||
|
await result.tracker.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("an auth switch detaches an in-flight old-account response and immediately fetches the new account", async () => {
|
||||||
|
const pending = Promise.withResolvers<unknown>();
|
||||||
|
const second = {
|
||||||
|
...plus,
|
||||||
|
account_id: "account-two",
|
||||||
|
rate_limit: {
|
||||||
|
...plus.rate_limit,
|
||||||
|
primary_window: { ...plus.rate_limit.primary_window, used_percent: 70 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const result = fixture(
|
||||||
|
{ type: "oauth", access: "old", refresh: "old", metadata: { accountID: "account-one" } },
|
||||||
|
[
|
||||||
|
pending.promise,
|
||||||
|
second,
|
||||||
|
{
|
||||||
|
...second,
|
||||||
|
rate_limit: {
|
||||||
|
...second.rate_limit,
|
||||||
|
primary_window: { ...second.rate_limit.primary_window, used_percent: 75 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
await result.tracker.init();
|
||||||
|
const old = result.tracker.start("root");
|
||||||
|
while (result.calls() === 0) await Bun.sleep(1);
|
||||||
|
result.switch({
|
||||||
|
type: "oauth",
|
||||||
|
access: "new",
|
||||||
|
refresh: "new",
|
||||||
|
metadata: { accountID: "account-two" },
|
||||||
|
});
|
||||||
|
await result.tracker.authChanged(true);
|
||||||
|
expect(result.calls()).toBe(2);
|
||||||
|
pending.resolve(plus);
|
||||||
|
await old;
|
||||||
|
expect((await result.tracker.status("root"))?.windows[0]?.used).toBe(70);
|
||||||
|
expect(result.headers[1]?.get("chatgpt-account-id")).toBe("account-two");
|
||||||
|
await result.tracker.refresh();
|
||||||
|
expect((await result.tracker.status("root"))?.windows[0]?.sessionConsumed).toBe(0);
|
||||||
|
await result.tracker.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("an auth switch during an old account storage read cannot restore stale state or polling", async () => {
|
||||||
|
const pending = Promise.withResolvers<Schema.Json | undefined>();
|
||||||
|
const second = {
|
||||||
|
...plus,
|
||||||
|
account_id: "account-two",
|
||||||
|
rate_limit: {
|
||||||
|
...plus.rate_limit,
|
||||||
|
primary_window: { ...plus.rate_limit.primary_window, used_percent: 64 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const result = fixture(
|
||||||
|
{ type: "oauth", access: "old", refresh: "old", metadata: { accountID: "account-one" } },
|
||||||
|
[second],
|
||||||
|
1_000_000,
|
||||||
|
[pending.promise],
|
||||||
|
);
|
||||||
|
const old = result.tracker.init();
|
||||||
|
while (result.storageCalls() === 0) await Bun.sleep(1);
|
||||||
|
result.switch({
|
||||||
|
type: "oauth",
|
||||||
|
access: "new",
|
||||||
|
refresh: "new",
|
||||||
|
metadata: { accountID: "account-two" },
|
||||||
|
});
|
||||||
|
await result.tracker.authChanged(true);
|
||||||
|
expect(result.calls()).toBe(1);
|
||||||
|
pending.resolve(undefined);
|
||||||
|
await old;
|
||||||
|
expect((await result.tracker.status("root"))?.windows[0]?.used).toBe(64);
|
||||||
|
expect(result.headers[0]?.get("chatgpt-account-id")).toBe("account-two");
|
||||||
|
await result.tracker.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("TUI quota loading converts RPC failures to an empty render state", async () => {
|
||||||
|
expect(
|
||||||
|
await loadQuotaStatus(async () => {
|
||||||
|
throw new Error("disconnected");
|
||||||
|
}),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { expect, test } from "bun:test";
|
||||||
|
import type { Plugin } from "@opencode/plugin/tui";
|
||||||
|
import { testRender, type JSX } from "@opentui/solid";
|
||||||
|
import { createSignal } from "solid-js";
|
||||||
|
import { build } from "../scripts/build.js";
|
||||||
|
import type { QuotaStatus } from "../src/quota.js";
|
||||||
|
|
||||||
|
type SlotRender = (input: { readonly sessionID: string }) => JSX.Element;
|
||||||
|
|
||||||
|
const status = (plan: string, remaining: number): QuotaStatus => ({
|
||||||
|
plan,
|
||||||
|
fetchedAt: 1,
|
||||||
|
windows: [
|
||||||
|
{
|
||||||
|
id: "codex:primary",
|
||||||
|
label: null,
|
||||||
|
seconds: 18_000,
|
||||||
|
used: 100 - remaining,
|
||||||
|
resetsAt: 2,
|
||||||
|
remaining,
|
||||||
|
sessionConsumed: 1.5,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
test("built quota slot stays reactive across pending, empty, failure, update, and session states", async () => {
|
||||||
|
await build();
|
||||||
|
// Resolve the built bundle at runtime; tsc runs before build creates dist/tui.js.
|
||||||
|
const tui: typeof import("../src/tui.js") = await import(
|
||||||
|
new URL("../dist/tui.js", import.meta.url).href
|
||||||
|
);
|
||||||
|
const { default: plugin } = tui;
|
||||||
|
const pending = Promise.withResolvers<QuotaStatus | null>();
|
||||||
|
const responses: Array<() => Promise<QuotaStatus | null>> = [() => pending.promise];
|
||||||
|
const sessions: string[] = [];
|
||||||
|
let slotRender: SlotRender | undefined;
|
||||||
|
let notifyUpdated: (() => void) | undefined;
|
||||||
|
|
||||||
|
const quota = {
|
||||||
|
status(input: { sessionID: string }) {
|
||||||
|
sessions.push(input.sessionID);
|
||||||
|
const response = responses.shift();
|
||||||
|
if (!response) throw new Error("Missing test response");
|
||||||
|
return response();
|
||||||
|
},
|
||||||
|
events: {
|
||||||
|
on(_event: "updated", callback: () => void) {
|
||||||
|
notifyUpdated = callback;
|
||||||
|
return () => undefined;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const contextFixture = {
|
||||||
|
client: { rpc: () => quota },
|
||||||
|
ui: {
|
||||||
|
slot(claim: { render: SlotRender }) {
|
||||||
|
slotRender = claim.render;
|
||||||
|
return () => undefined;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
theme: { text: { default: "#ffffff", muted: "#888888" } },
|
||||||
|
};
|
||||||
|
// SAFETY: The slot setup only reads the client RPC, slot registration, and theme
|
||||||
|
// members implemented by this focused rendering fixture.
|
||||||
|
const context = Object.assign({} as Plugin.Context, contextFixture);
|
||||||
|
const cleanup = await plugin.setup(context);
|
||||||
|
if (!slotRender || !notifyUpdated) throw new Error("Plugin did not register its slot");
|
||||||
|
|
||||||
|
const [sessionID, setSessionID] = createSignal("session-one");
|
||||||
|
const renderSlot = slotRender;
|
||||||
|
const setup = await testRender(
|
||||||
|
() =>
|
||||||
|
renderSlot({
|
||||||
|
get sessionID() {
|
||||||
|
return sessionID();
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{ width: 70, height: 5 },
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await setup.renderOnce();
|
||||||
|
expect(setup.captureCharFrame()).not.toContain("ChatGPT quota");
|
||||||
|
|
||||||
|
pending.resolve(status("plus", 75));
|
||||||
|
await setup.waitForFrame((frame) => frame.includes("ChatGPT quota (plus)"));
|
||||||
|
expect(setup.captureCharFrame()).toContain("5h: 75% left · ~1.5pp this session");
|
||||||
|
|
||||||
|
responses.push(async () => null);
|
||||||
|
notifyUpdated();
|
||||||
|
await setup.waitForFrame((frame) => !frame.includes("ChatGPT quota"));
|
||||||
|
|
||||||
|
responses.push(async () => {
|
||||||
|
throw new Error("disconnected");
|
||||||
|
});
|
||||||
|
notifyUpdated();
|
||||||
|
await setup.waitFor(() => sessions.length === 3);
|
||||||
|
expect(setup.captureCharFrame()).not.toContain("ChatGPT quota");
|
||||||
|
|
||||||
|
responses.push(async () => status("pro", 42));
|
||||||
|
setSessionID("session-two");
|
||||||
|
await setup.waitForFrame((frame) => frame.includes("ChatGPT quota (pro)"));
|
||||||
|
expect(sessions).toEqual(["session-one", "session-one", "session-one", "session-two"]);
|
||||||
|
} finally {
|
||||||
|
setup.renderer.destroy();
|
||||||
|
if (cleanup) await cleanup();
|
||||||
|
}
|
||||||
|
});
|
||||||
+1
-1
@@ -3,5 +3,5 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"rootDir": "src"
|
"rootDir": "src"
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts"]
|
"include": ["src/**/*.ts", "src/**/*.tsx"]
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -12,10 +12,12 @@
|
|||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"verbatimModuleSyntax": true,
|
"verbatimModuleSyntax": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "@opentui/solid",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"rootDir": ".",
|
"rootDir": ".",
|
||||||
"outDir": "dist"
|
"outDir": "dist"
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "tests/**/*.ts"]
|
"include": ["src/**/*.ts", "src/**/*.tsx", "scripts/**/*.ts", "tests/**/*.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user