mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-16 01:19:19 -04:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b77dbb511e | |||
| 8952cef65f |
@@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
"@opencode-ai/cli": patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Expose a TUI plugin slot at the top of the session view.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
---
|
|
||||||
"@opencode-ai/client": patch
|
|
||||||
"@opencode-ai/plugin": patch
|
|
||||||
"@opencode-ai/protocol": patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Expose transient, read-only session generation through the HTTP API, generated clients, and V2 plugin session context.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
"@opencode-ai/cli": patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Expose a TUI plugin slot above the session composer.
|
|
||||||
@@ -1,3 +1,2 @@
|
|||||||
packages/core/migration/**/snapshot.json linguist-generated
|
packages/core/migration/**/snapshot.json linguist-generated
|
||||||
packages/core/src/database/migration.gen.ts linguist-generated
|
packages/core/src/database/migration.gen.ts linguist-generated
|
||||||
packages/core/src/**/*.txt text eol=lf
|
|
||||||
|
|||||||
@@ -121,55 +121,6 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
version: ${{ needs.version.outputs.version }}
|
version: ${{ needs.version.outputs.version }}
|
||||||
|
|
||||||
build-node-cli:
|
|
||||||
needs: version
|
|
||||||
if: github.repository == 'anomalyco/opencode'
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
settings:
|
|
||||||
- target: linux-arm64
|
|
||||||
host: blacksmith-4vcpu-ubuntu-2404-arm
|
|
||||||
- target: linux-x64
|
|
||||||
host: blacksmith-4vcpu-ubuntu-2404
|
|
||||||
- target: darwin-arm64
|
|
||||||
host: macos-26
|
|
||||||
- target: windows-arm64
|
|
||||||
host: blacksmith-4vcpu-windows-2025
|
|
||||||
- target: windows-x64
|
|
||||||
host: blacksmith-4vcpu-windows-2025
|
|
||||||
runs-on: ${{ matrix.settings.host }}
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
|
||||||
|
|
||||||
- uses: ./.github/actions/setup-bun
|
|
||||||
with:
|
|
||||||
install-flags: --os=* --cpu=*
|
|
||||||
|
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
||||||
with:
|
|
||||||
node-version: "26.4.0"
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: bun packages/cli/script/build-node.ts --target=${{ matrix.settings.target }} --skip-install --outdir=dist/node
|
|
||||||
env:
|
|
||||||
OPENCODE_VERSION: ${{ needs.version.outputs.version }}
|
|
||||||
OPENCODE_RELEASE: ${{ needs.version.outputs.release }}
|
|
||||||
|
|
||||||
- name: Verify service lifecycle
|
|
||||||
if: matrix.settings.target != 'windows-arm64'
|
|
||||||
working-directory: packages/cli
|
|
||||||
run: bun run script/service-smoke.ts --node
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
||||||
with:
|
|
||||||
name: opencode-node-cli-${{ matrix.settings.target }}
|
|
||||||
path: packages/cli/dist/node/cli-node-*
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
sign-cli-windows:
|
sign-cli-windows:
|
||||||
needs:
|
needs:
|
||||||
- build-cli
|
- build-cli
|
||||||
@@ -462,7 +413,6 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- version
|
- version
|
||||||
- build-cli
|
- build-cli
|
||||||
- build-node-cli
|
|
||||||
- sign-cli-windows
|
- sign-cli-windows
|
||||||
- build-electron
|
- build-electron
|
||||||
if: always() && !failure() && !cancelled()
|
if: always() && !failure() && !cancelled()
|
||||||
@@ -511,12 +461,6 @@ jobs:
|
|||||||
name: opencode-preview-cli
|
name: opencode-preview-cli
|
||||||
path: packages/cli/dist
|
path: packages/cli/dist
|
||||||
|
|
||||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
||||||
with:
|
|
||||||
pattern: opencode-node-cli-*
|
|
||||||
path: packages/cli/dist/node
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||||
if: needs.version.outputs.release
|
if: needs.version.outputs.release
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -78,20 +78,6 @@ jobs:
|
|||||||
bun run script/build.ts --single --skip-install
|
bun run script/build.ts --single --skip-install
|
||||||
bun run script/service-smoke.ts
|
bun run script/service-smoke.ts
|
||||||
|
|
||||||
- name: Setup Node build runtime
|
|
||||||
if: always()
|
|
||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
||||||
with:
|
|
||||||
node-version: "26.4.0"
|
|
||||||
|
|
||||||
- name: Verify Node build
|
|
||||||
if: always()
|
|
||||||
timeout-minutes: 15
|
|
||||||
working-directory: packages/cli
|
|
||||||
run: |
|
|
||||||
bun run script/build-node.ts --single --skip-install --outdir=dist/node
|
|
||||||
bun run script/service-smoke.ts --node
|
|
||||||
|
|
||||||
- name: Check generated client
|
- name: Check generated client
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
working-directory: packages/client
|
working-directory: packages/client
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ node_modules
|
|||||||
playground
|
playground
|
||||||
tmp
|
tmp
|
||||||
dist
|
dist
|
||||||
dist-node
|
|
||||||
ts-dist
|
ts-dist
|
||||||
.turbo
|
.turbo
|
||||||
.typecheck-profiles
|
.typecheck-profiles
|
||||||
@@ -26,7 +25,6 @@ Session.vim
|
|||||||
a.out
|
a.out
|
||||||
target
|
target
|
||||||
.scripts
|
.scripts
|
||||||
.cache
|
|
||||||
.direnv/
|
.direnv/
|
||||||
|
|
||||||
# Local dev files
|
# Local dev files
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ Valid types are `feat`, `fix`, `docs`, `chore`, `refactor`, and `test`. Scopes a
|
|||||||
|
|
||||||
Examples: `fix(tui): simplify thinking toggle styling`, `docs: update contributing guide`, `chore(sdk): regenerate types`.
|
Examples: `fix(tui): simplify thinking toggle styling`, `docs: update contributing guide`, `chore(sdk): regenerate types`.
|
||||||
|
|
||||||
|
Never bypass Git hooks. Do not use `--no-verify` or otherwise disable, skip, or circumvent commit or push hooks. If a hook fails, fix the failure or stop and report it to the user.
|
||||||
|
|
||||||
## Style Guide
|
## Style Guide
|
||||||
|
|
||||||
### General Principles
|
### General Principles
|
||||||
|
|||||||
@@ -30,30 +30,9 @@
|
|||||||
"turbo": "2.10.2",
|
"turbo": "2.10.2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages/ai": {
|
|
||||||
"name": "@opencode-ai/ai",
|
|
||||||
"version": "1.17.20",
|
|
||||||
"dependencies": {
|
|
||||||
"@opencode-ai/schema": "workspace:*",
|
|
||||||
"@smithy/eventstream-codec": "4.2.14",
|
|
||||||
"@smithy/util-utf8": "4.2.2",
|
|
||||||
"aws4fetch": "1.0.20",
|
|
||||||
"effect": "catalog:",
|
|
||||||
"google-auth-library": "10.5.0",
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@clack/prompts": "1.0.0-alpha.1",
|
|
||||||
"@effect/platform-node": "catalog:",
|
|
||||||
"@opencode-ai/http-recorder": "workspace:*",
|
|
||||||
"@tsconfig/bun": "catalog:",
|
|
||||||
"@types/bun": "catalog:",
|
|
||||||
"@typescript/native-preview": "catalog:",
|
|
||||||
"typescript": "catalog:",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"packages/app": {
|
"packages/app": {
|
||||||
"name": "@opencode-ai/app",
|
"name": "@opencode-ai/app",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@corvu/drawer": "catalog:",
|
"@corvu/drawer": "catalog:",
|
||||||
"@dnd-kit/abstract": "0.5.0",
|
"@dnd-kit/abstract": "0.5.0",
|
||||||
@@ -119,7 +98,7 @@
|
|||||||
},
|
},
|
||||||
"packages/cli": {
|
"packages/cli": {
|
||||||
"name": "@opencode-ai/cli",
|
"name": "@opencode-ai/cli",
|
||||||
"version": "1.18.3",
|
"version": "1.17.18",
|
||||||
"bin": {
|
"bin": {
|
||||||
"opencode2": "./bin/opencode2.cjs",
|
"opencode2": "./bin/opencode2.cjs",
|
||||||
},
|
},
|
||||||
@@ -145,28 +124,14 @@
|
|||||||
"solid-js": "catalog:",
|
"solid-js": "catalog:",
|
||||||
"strip-ansi": "7.1.2",
|
"strip-ansi": "7.1.2",
|
||||||
"uqr": "0.1.3",
|
"uqr": "0.1.3",
|
||||||
"ws": "8.21.0",
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@lydell/node-pty-darwin-arm64": "1.2.0-beta.12",
|
|
||||||
"@lydell/node-pty-darwin-x64": "1.2.0-beta.12",
|
|
||||||
"@lydell/node-pty-linux-arm64": "1.2.0-beta.12",
|
|
||||||
"@lydell/node-pty-linux-x64": "1.2.0-beta.12",
|
|
||||||
"@lydell/node-pty-win32-arm64": "1.2.0-beta.12",
|
|
||||||
"@lydell/node-pty-win32-x64": "1.2.0-beta.12",
|
|
||||||
"@opencode-ai/protocol": "workspace:*",
|
"@opencode-ai/protocol": "workspace:*",
|
||||||
"@opencode-ai/script": "workspace:*",
|
"@opencode-ai/script": "workspace:*",
|
||||||
"@parcel/watcher-darwin-arm64": "2.5.1",
|
|
||||||
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
|
|
||||||
"@parcel/watcher-linux-x64-glibc": "2.5.1",
|
|
||||||
"@parcel/watcher-win32-arm64": "2.5.1",
|
|
||||||
"@parcel/watcher-win32-x64": "2.5.1",
|
|
||||||
"@tsconfig/bun": "catalog:",
|
"@tsconfig/bun": "catalog:",
|
||||||
"@types/bun": "catalog:",
|
"@types/bun": "catalog:",
|
||||||
"@types/semver": "catalog:",
|
"@types/semver": "catalog:",
|
||||||
"@typescript/native-preview": "catalog:",
|
"@typescript/native-preview": "catalog:",
|
||||||
"vite": "catalog:",
|
|
||||||
"vite-plugin-solid": "catalog:",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages/client": {
|
"packages/client": {
|
||||||
@@ -185,7 +150,7 @@
|
|||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"effect": "4.0.0-beta.98",
|
"effect": "4.0.0-beta.83",
|
||||||
},
|
},
|
||||||
"optionalPeers": [
|
"optionalPeers": [
|
||||||
"effect",
|
"effect",
|
||||||
@@ -193,7 +158,7 @@
|
|||||||
},
|
},
|
||||||
"packages/codemode": {
|
"packages/codemode": {
|
||||||
"name": "@opencode-ai/codemode",
|
"name": "@opencode-ai/codemode",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "8.15.0",
|
"acorn": "8.15.0",
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
@@ -203,11 +168,12 @@
|
|||||||
"@tsconfig/bun": "catalog:",
|
"@tsconfig/bun": "catalog:",
|
||||||
"@types/bun": "catalog:",
|
"@types/bun": "catalog:",
|
||||||
"@typescript/native-preview": "catalog:",
|
"@typescript/native-preview": "catalog:",
|
||||||
|
"typescript": "catalog:",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages/console/app": {
|
"packages/console/app": {
|
||||||
"name": "@opencode-ai/console-app",
|
"name": "@opencode-ai/console-app",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cloudflare/vite-plugin": "1.15.2",
|
"@cloudflare/vite-plugin": "1.15.2",
|
||||||
"@ibm/plex": "6.4.1",
|
"@ibm/plex": "6.4.1",
|
||||||
@@ -243,7 +209,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/core": {
|
"packages/console/core": {
|
||||||
"name": "@opencode-ai/console-core",
|
"name": "@opencode-ai/console-core",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-sts": "3.782.0",
|
"@aws-sdk/client-sts": "3.782.0",
|
||||||
"@jsx-email/render": "1.1.1",
|
"@jsx-email/render": "1.1.1",
|
||||||
@@ -270,7 +236,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/function": {
|
"packages/console/function": {
|
||||||
"name": "@opencode-ai/console-function",
|
"name": "@opencode-ai/console-function",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/anthropic": "3.0.82",
|
"@ai-sdk/anthropic": "3.0.82",
|
||||||
"@ai-sdk/openai": "3.0.48",
|
"@ai-sdk/openai": "3.0.48",
|
||||||
@@ -292,7 +258,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/mail": {
|
"packages/console/mail": {
|
||||||
"name": "@opencode-ai/console-mail",
|
"name": "@opencode-ai/console-mail",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jsx-email/all": "2.2.3",
|
"@jsx-email/all": "2.2.3",
|
||||||
"@jsx-email/cli": "1.4.3",
|
"@jsx-email/cli": "1.4.3",
|
||||||
@@ -316,7 +282,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/support": {
|
"packages/console/support": {
|
||||||
"name": "@opencode-ai/console-support",
|
"name": "@opencode-ai/console-support",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cloudflare/vite-plugin": "1.15.2",
|
"@cloudflare/vite-plugin": "1.15.2",
|
||||||
"@opencode-ai/console-core": "workspace:*",
|
"@opencode-ai/console-core": "workspace:*",
|
||||||
@@ -336,7 +302,7 @@
|
|||||||
},
|
},
|
||||||
"packages/core": {
|
"packages/core": {
|
||||||
"name": "@opencode-ai/core",
|
"name": "@opencode-ai/core",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"bin": {
|
"bin": {
|
||||||
"opencode": "./bin/opencode",
|
"opencode": "./bin/opencode",
|
||||||
},
|
},
|
||||||
@@ -370,10 +336,10 @@
|
|||||||
"@modelcontextprotocol/sdk": "1.29.0",
|
"@modelcontextprotocol/sdk": "1.29.0",
|
||||||
"@npmcli/arborist": "9.4.0",
|
"@npmcli/arborist": "9.4.0",
|
||||||
"@npmcli/config": "10.8.1",
|
"@npmcli/config": "10.8.1",
|
||||||
"@opencode-ai/ai": "workspace:*",
|
|
||||||
"@opencode-ai/codemode": "workspace:*",
|
"@opencode-ai/codemode": "workspace:*",
|
||||||
"@opencode-ai/effect-drizzle-sqlite": "workspace:*",
|
"@opencode-ai/effect-drizzle-sqlite": "workspace:*",
|
||||||
"@opencode-ai/effect-sqlite-node": "workspace:*",
|
"@opencode-ai/effect-sqlite-node": "workspace:*",
|
||||||
|
"@opencode-ai/ai": "workspace:*",
|
||||||
"@opencode-ai/plugin": "workspace:*",
|
"@opencode-ai/plugin": "workspace:*",
|
||||||
"@opencode-ai/schema": "workspace:*",
|
"@opencode-ai/schema": "workspace:*",
|
||||||
"@openrouter/ai-sdk-provider": "2.9.0",
|
"@openrouter/ai-sdk-provider": "2.9.0",
|
||||||
@@ -401,7 +367,6 @@
|
|||||||
"mime-types": "3.0.2",
|
"mime-types": "3.0.2",
|
||||||
"minimatch": "10.2.5",
|
"minimatch": "10.2.5",
|
||||||
"npm-package-arg": "13.0.2",
|
"npm-package-arg": "13.0.2",
|
||||||
"resolve.exports": "catalog:",
|
|
||||||
"semver": "^7.6.3",
|
"semver": "^7.6.3",
|
||||||
"turndown": "7.2.0",
|
"turndown": "7.2.0",
|
||||||
"venice-ai-sdk-provider": "2.1.1",
|
"venice-ai-sdk-provider": "2.1.1",
|
||||||
@@ -433,7 +398,7 @@
|
|||||||
},
|
},
|
||||||
"packages/desktop": {
|
"packages/desktop": {
|
||||||
"name": "@opencode-ai/desktop",
|
"name": "@opencode-ai/desktop",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@zip.js/zip.js": "2.7.62",
|
"@zip.js/zip.js": "2.7.62",
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
@@ -493,7 +458,7 @@
|
|||||||
},
|
},
|
||||||
"packages/effect-drizzle-sqlite": {
|
"packages/effect-drizzle-sqlite": {
|
||||||
"name": "@opencode-ai/effect-drizzle-sqlite",
|
"name": "@opencode-ai/effect-drizzle-sqlite",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"drizzle-orm": "catalog:",
|
"drizzle-orm": "catalog:",
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
@@ -507,7 +472,7 @@
|
|||||||
},
|
},
|
||||||
"packages/effect-sqlite-node": {
|
"packages/effect-sqlite-node": {
|
||||||
"name": "@opencode-ai/effect-sqlite-node",
|
"name": "@opencode-ai/effect-sqlite-node",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
},
|
},
|
||||||
@@ -519,7 +484,7 @@
|
|||||||
},
|
},
|
||||||
"packages/enterprise": {
|
"packages/enterprise": {
|
||||||
"name": "@opencode-ai/enterprise",
|
"name": "@opencode-ai/enterprise",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hono/standard-validator": "catalog:",
|
"@hono/standard-validator": "catalog:",
|
||||||
"@opencode-ai/core": "workspace:*",
|
"@opencode-ai/core": "workspace:*",
|
||||||
@@ -551,7 +516,7 @@
|
|||||||
},
|
},
|
||||||
"packages/function": {
|
"packages/function": {
|
||||||
"name": "@opencode-ai/function",
|
"name": "@opencode-ai/function",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/auth-app": "8.0.1",
|
"@octokit/auth-app": "8.0.1",
|
||||||
"@octokit/rest": "catalog:",
|
"@octokit/rest": "catalog:",
|
||||||
@@ -567,9 +532,9 @@
|
|||||||
},
|
},
|
||||||
"packages/http-recorder": {
|
"packages/http-recorder": {
|
||||||
"name": "@opencode-ai/http-recorder",
|
"name": "@opencode-ai/http-recorder",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@effect/platform-node-shared": "4.0.0-beta.98",
|
"@effect/platform-node-shared": "4.0.0-beta.83",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@effect/platform-node": "catalog:",
|
"@effect/platform-node": "catalog:",
|
||||||
@@ -597,9 +562,29 @@
|
|||||||
"@typescript/native-preview": "catalog:",
|
"@typescript/native-preview": "catalog:",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"packages/ai": {
|
||||||
|
"name": "@opencode-ai/ai",
|
||||||
|
"version": "1.17.20",
|
||||||
|
"dependencies": {
|
||||||
|
"@opencode-ai/schema": "workspace:*",
|
||||||
|
"@smithy/eventstream-codec": "4.2.14",
|
||||||
|
"@smithy/util-utf8": "4.2.2",
|
||||||
|
"aws4fetch": "1.0.20",
|
||||||
|
"effect": "catalog:",
|
||||||
|
"google-auth-library": "10.5.0",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@clack/prompts": "1.0.0-alpha.1",
|
||||||
|
"@effect/platform-node": "catalog:",
|
||||||
|
"@opencode-ai/http-recorder": "workspace:*",
|
||||||
|
"@tsconfig/bun": "catalog:",
|
||||||
|
"@types/bun": "catalog:",
|
||||||
|
"@typescript/native-preview": "catalog:",
|
||||||
|
},
|
||||||
|
},
|
||||||
"packages/opencode": {
|
"packages/opencode": {
|
||||||
"name": "opencode",
|
"name": "opencode",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"bin": {
|
"bin": {
|
||||||
"opencode": "./bin/opencode",
|
"opencode": "./bin/opencode",
|
||||||
},
|
},
|
||||||
@@ -636,10 +621,10 @@
|
|||||||
"@octokit/graphql": "9.0.2",
|
"@octokit/graphql": "9.0.2",
|
||||||
"@octokit/rest": "catalog:",
|
"@octokit/rest": "catalog:",
|
||||||
"@openauthjs/openauth": "catalog:",
|
"@openauthjs/openauth": "catalog:",
|
||||||
"@opencode-ai/ai": "workspace:*",
|
|
||||||
"@opencode-ai/cli": "workspace:*",
|
"@opencode-ai/cli": "workspace:*",
|
||||||
"@opencode-ai/client": "workspace:*",
|
"@opencode-ai/client": "workspace:*",
|
||||||
"@opencode-ai/codemode": "workspace:*",
|
"@opencode-ai/codemode": "workspace:*",
|
||||||
|
"@opencode-ai/ai": "workspace:*",
|
||||||
"@opencode-ai/plugin": "workspace:*",
|
"@opencode-ai/plugin": "workspace:*",
|
||||||
"@opencode-ai/protocol": "workspace:*",
|
"@opencode-ai/protocol": "workspace:*",
|
||||||
"@opencode-ai/schema": "workspace:*",
|
"@opencode-ai/schema": "workspace:*",
|
||||||
@@ -732,14 +717,12 @@
|
|||||||
},
|
},
|
||||||
"packages/plugin": {
|
"packages/plugin": {
|
||||||
"name": "@opencode-ai/plugin",
|
"name": "@opencode-ai/plugin",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/provider": "3.0.8",
|
"@ai-sdk/provider": "3.0.8",
|
||||||
"@opencode-ai/ai": "workspace:*",
|
|
||||||
"@opencode-ai/client": "workspace:*",
|
"@opencode-ai/client": "workspace:*",
|
||||||
"@opencode-ai/schema": "workspace:*",
|
"@opencode-ai/schema": "workspace:*",
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
"@standard-schema/spec": "^1.1.0",
|
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
"zod": "catalog:",
|
"zod": "catalog:",
|
||||||
},
|
},
|
||||||
@@ -754,9 +737,9 @@
|
|||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@opentui/core": ">=0.4.5",
|
"@opentui/core": ">=0.4.3",
|
||||||
"@opentui/keymap": ">=0.4.5",
|
"@opentui/keymap": ">=0.4.3",
|
||||||
"@opentui/solid": ">=0.4.5",
|
"@opentui/solid": ">=0.4.3",
|
||||||
},
|
},
|
||||||
"optionalPeers": [
|
"optionalPeers": [
|
||||||
"@opentui/core",
|
"@opentui/core",
|
||||||
@@ -821,7 +804,7 @@
|
|||||||
},
|
},
|
||||||
"packages/sdk/js": {
|
"packages/sdk/js": {
|
||||||
"name": "@opencode-ai/sdk",
|
"name": "@opencode-ai/sdk",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-spawn": "catalog:",
|
"cross-spawn": "catalog:",
|
||||||
},
|
},
|
||||||
@@ -836,7 +819,7 @@
|
|||||||
},
|
},
|
||||||
"packages/server": {
|
"packages/server": {
|
||||||
"name": "@opencode-ai/server",
|
"name": "@opencode-ai/server",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@effect/platform-node": "catalog:",
|
"@effect/platform-node": "catalog:",
|
||||||
"@opencode-ai/core": "workspace:*",
|
"@opencode-ai/core": "workspace:*",
|
||||||
@@ -853,7 +836,7 @@
|
|||||||
},
|
},
|
||||||
"packages/session-ui": {
|
"packages/session-ui": {
|
||||||
"name": "@opencode-ai/session-ui",
|
"name": "@opencode-ai/session-ui",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kobalte/core": "catalog:",
|
"@kobalte/core": "catalog:",
|
||||||
"@opencode-ai/core": "workspace:*",
|
"@opencode-ai/core": "workspace:*",
|
||||||
@@ -901,8 +884,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/commit-mono": "5.2.5",
|
"@fontsource/commit-mono": "5.2.5",
|
||||||
"@napi-rs/canvas": "1.0.2",
|
"@napi-rs/canvas": "1.0.2",
|
||||||
"@opencode-ai/ai": "workspace:*",
|
|
||||||
"@opencode-ai/core": "workspace:*",
|
"@opencode-ai/core": "workspace:*",
|
||||||
|
"@opencode-ai/ai": "workspace:*",
|
||||||
"@opentui/core": "catalog:",
|
"@opentui/core": "catalog:",
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
},
|
},
|
||||||
@@ -914,7 +897,7 @@
|
|||||||
},
|
},
|
||||||
"packages/slack": {
|
"packages/slack": {
|
||||||
"name": "@opencode-ai/slack",
|
"name": "@opencode-ai/slack",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
"@slack/bolt": "^3.17.1",
|
"@slack/bolt": "^3.17.1",
|
||||||
@@ -927,7 +910,7 @@
|
|||||||
},
|
},
|
||||||
"packages/stats/app": {
|
"packages/stats/app": {
|
||||||
"name": "@opencode-ai/stats-app",
|
"name": "@opencode-ai/stats-app",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ibm/plex": "6.4.1",
|
"@ibm/plex": "6.4.1",
|
||||||
"@kobalte/core": "catalog:",
|
"@kobalte/core": "catalog:",
|
||||||
@@ -961,7 +944,7 @@
|
|||||||
},
|
},
|
||||||
"packages/stats/core": {
|
"packages/stats/core": {
|
||||||
"name": "@opencode-ai/stats-core",
|
"name": "@opencode-ai/stats-core",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-athena": "3.933.0",
|
"@aws-sdk/client-athena": "3.933.0",
|
||||||
"@planetscale/database": "1.19.0",
|
"@planetscale/database": "1.19.0",
|
||||||
@@ -980,7 +963,7 @@
|
|||||||
},
|
},
|
||||||
"packages/stats/server": {
|
"packages/stats/server": {
|
||||||
"name": "@opencode-ai/stats-server",
|
"name": "@opencode-ai/stats-server",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-firehose": "3.933.0",
|
"@aws-sdk/client-firehose": "3.933.0",
|
||||||
"@effect/platform-node": "catalog:",
|
"@effect/platform-node": "catalog:",
|
||||||
@@ -1021,7 +1004,7 @@
|
|||||||
},
|
},
|
||||||
"packages/tui": {
|
"packages/tui": {
|
||||||
"name": "@opencode-ai/tui",
|
"name": "@opencode-ai/tui",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/client": "workspace:*",
|
"@opencode-ai/client": "workspace:*",
|
||||||
"@opencode-ai/core": "workspace:*",
|
"@opencode-ai/core": "workspace:*",
|
||||||
@@ -1036,12 +1019,10 @@
|
|||||||
"diff": "catalog:",
|
"diff": "catalog:",
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
"fuzzysort": "catalog:",
|
"fuzzysort": "catalog:",
|
||||||
"get-east-asian-width": "catalog:",
|
|
||||||
"open": "10.1.2",
|
"open": "10.1.2",
|
||||||
"opentui-spinner": "catalog:",
|
"opentui-spinner": "catalog:",
|
||||||
"remeda": "catalog:",
|
"remeda": "catalog:",
|
||||||
"solid-js": "catalog:",
|
"solid-js": "catalog:",
|
||||||
"string-width": "catalog:",
|
|
||||||
"strip-ansi": "7.1.2",
|
"strip-ansi": "7.1.2",
|
||||||
"uqr": "0.1.3",
|
"uqr": "0.1.3",
|
||||||
},
|
},
|
||||||
@@ -1053,7 +1034,7 @@
|
|||||||
},
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
"name": "@opencode-ai/ui",
|
"name": "@opencode-ai/ui",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kobalte/core": "catalog:",
|
"@kobalte/core": "catalog:",
|
||||||
"@pierre/diffs": "catalog:",
|
"@pierre/diffs": "catalog:",
|
||||||
@@ -1104,7 +1085,7 @@
|
|||||||
},
|
},
|
||||||
"packages/web": {
|
"packages/web": {
|
||||||
"name": "@opencode-ai/web",
|
"name": "@opencode-ai/web",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/cloudflare": "12.6.3",
|
"@astrojs/cloudflare": "12.6.3",
|
||||||
"@astrojs/markdown-remark": "6.3.1",
|
"@astrojs/markdown-remark": "6.3.1",
|
||||||
@@ -1180,12 +1161,12 @@
|
|||||||
"@modelcontextprotocol/sdk@1.29.0": "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch",
|
"@modelcontextprotocol/sdk@1.29.0": "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch",
|
||||||
"gcp-metadata@8.1.2": "patches/gcp-metadata@8.1.2.patch",
|
"gcp-metadata@8.1.2": "patches/gcp-metadata@8.1.2.patch",
|
||||||
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
|
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
|
||||||
|
"effect@4.0.0-beta.83": "patches/effect@4.0.0-beta.83.patch",
|
||||||
"@npmcli/agent@4.0.2": "patches/@npmcli%2Fagent@4.0.2.patch",
|
"@npmcli/agent@4.0.2": "patches/@npmcli%2Fagent@4.0.2.patch",
|
||||||
"@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch",
|
"@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch",
|
||||||
"solid-js@1.9.10": "patches/solid-js@1.9.10.patch",
|
"solid-js@1.9.10": "patches/solid-js@1.9.10.patch",
|
||||||
"@ai-sdk/google@3.0.73": "patches/@ai-sdk%2Fgoogle@3.0.73.patch",
|
"@ai-sdk/google@3.0.73": "patches/@ai-sdk%2Fgoogle@3.0.73.patch",
|
||||||
"pacote@21.5.0": "patches/pacote@21.5.0.patch",
|
"pacote@21.5.0": "patches/pacote@21.5.0.patch",
|
||||||
"effect@4.0.0-beta.98": "patches/effect@4.0.0-beta.98.patch",
|
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"@opentui/core": "catalog:",
|
"@opentui/core": "catalog:",
|
||||||
@@ -1197,9 +1178,9 @@
|
|||||||
"catalog": {
|
"catalog": {
|
||||||
"@cloudflare/workers-types": "4.20251008.0",
|
"@cloudflare/workers-types": "4.20251008.0",
|
||||||
"@corvu/drawer": "0.2.4",
|
"@corvu/drawer": "0.2.4",
|
||||||
"@effect/opentelemetry": "4.0.0-beta.98",
|
"@effect/opentelemetry": "4.0.0-beta.83",
|
||||||
"@effect/platform-node": "4.0.0-beta.98",
|
"@effect/platform-node": "4.0.0-beta.83",
|
||||||
"@effect/sql-sqlite-bun": "4.0.0-beta.98",
|
"@effect/sql-sqlite-bun": "4.0.0-beta.83",
|
||||||
"@hono/standard-validator": "0.2.0",
|
"@hono/standard-validator": "0.2.0",
|
||||||
"@hono/zod-validator": "0.4.2",
|
"@hono/zod-validator": "0.4.2",
|
||||||
"@kobalte/core": "0.13.11",
|
"@kobalte/core": "0.13.11",
|
||||||
@@ -1207,9 +1188,9 @@
|
|||||||
"@npmcli/arborist": "9.4.0",
|
"@npmcli/arborist": "9.4.0",
|
||||||
"@octokit/rest": "22.0.0",
|
"@octokit/rest": "22.0.0",
|
||||||
"@openauthjs/openauth": "0.0.0-20250322224806",
|
"@openauthjs/openauth": "0.0.0-20250322224806",
|
||||||
"@opentui/core": "0.4.5",
|
"@opentui/core": "0.4.3",
|
||||||
"@opentui/keymap": "0.4.5",
|
"@opentui/keymap": "0.4.3",
|
||||||
"@opentui/solid": "0.4.5",
|
"@opentui/solid": "0.4.3",
|
||||||
"@pierre/diffs": "1.2.10",
|
"@pierre/diffs": "1.2.10",
|
||||||
"@playwright/test": "1.59.1",
|
"@playwright/test": "1.59.1",
|
||||||
"@sentry/solid": "10.36.0",
|
"@sentry/solid": "10.36.0",
|
||||||
@@ -1235,9 +1216,8 @@
|
|||||||
"dompurify": "3.3.1",
|
"dompurify": "3.3.1",
|
||||||
"drizzle-kit": "1.0.0-rc.2",
|
"drizzle-kit": "1.0.0-rc.2",
|
||||||
"drizzle-orm": "1.0.0-rc.2",
|
"drizzle-orm": "1.0.0-rc.2",
|
||||||
"effect": "4.0.0-beta.98",
|
"effect": "4.0.0-beta.83",
|
||||||
"fuzzysort": "3.1.0",
|
"fuzzysort": "3.1.0",
|
||||||
"get-east-asian-width": "1.6.0",
|
|
||||||
"hono": "4.10.7",
|
"hono": "4.10.7",
|
||||||
"hono-openapi": "1.1.2",
|
"hono-openapi": "1.1.2",
|
||||||
"luxon": "3.6.1",
|
"luxon": "3.6.1",
|
||||||
@@ -1246,13 +1226,11 @@
|
|||||||
"opentui-spinner": "0.0.7",
|
"opentui-spinner": "0.0.7",
|
||||||
"remeda": "2.26.0",
|
"remeda": "2.26.0",
|
||||||
"remend": "1.3.0",
|
"remend": "1.3.0",
|
||||||
"resolve.exports": "2.0.3",
|
|
||||||
"semver": "7.7.4",
|
"semver": "7.7.4",
|
||||||
"shiki": "4.2.0",
|
"shiki": "4.2.0",
|
||||||
"solid-js": "1.9.10",
|
"solid-js": "1.9.10",
|
||||||
"solid-list": "0.3.0",
|
"solid-list": "0.3.0",
|
||||||
"sst": "4.13.1",
|
"sst": "4.13.1",
|
||||||
"string-width": "7.2.0",
|
|
||||||
"tailwindcss": "4.1.11",
|
"tailwindcss": "4.1.11",
|
||||||
"typescript": "5.8.2",
|
"typescript": "5.8.2",
|
||||||
"ulid": "3.0.1",
|
"ulid": "3.0.1",
|
||||||
@@ -1639,13 +1617,13 @@
|
|||||||
|
|
||||||
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.11.0", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="],
|
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.11.0", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="],
|
||||||
|
|
||||||
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-beta.98", "", { "peerDependencies": { "@opentelemetry/api": "^1.9", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": "^2.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": "^2.0.0", "@opentelemetry/sdk-trace-base": "^2.0.0", "@opentelemetry/sdk-trace-node": "^2.0.0", "@opentelemetry/sdk-trace-web": "^2.0.0", "@opentelemetry/semantic-conventions": "^1.33.0", "effect": "^4.0.0-beta.98" }, "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-ITfK8xhcl+9GXOvPwzADWkOQ+dgUGZrJNefT3r2+uLFmzjyKRLtHzhLOl6lZaLSsf5io13+nmt8adfMRQPq+oA=="],
|
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-beta.83", "", { "peerDependencies": { "@opentelemetry/api": "^1.9", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": "^2.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": "^2.0.0", "@opentelemetry/sdk-trace-base": "^2.0.0", "@opentelemetry/sdk-trace-node": "^2.0.0", "@opentelemetry/sdk-trace-web": "^2.0.0", "@opentelemetry/semantic-conventions": "^1.33.0", "effect": "^4.0.0-beta.83" }, "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-cPfCfp/ghu0itbX6Dqjdr4N0rbjng5ON4sUpnLHV5JJySG8zZpWmuOZLWIrfrNKT2ctYR1BYmp1aYCgkItaJLw=="],
|
||||||
|
|
||||||
"@effect/platform-node": ["@effect/platform-node@4.0.0-beta.98", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.98", "mime": "^4.1.0", "undici": "^8.7.0" }, "peerDependencies": { "effect": "^4.0.0-beta.98", "ioredis": "^5.7.0" } }, "sha512-IQu1TiLXQEDSGkDBllyYjVadf+UqdjptryqX4mmktVTTbGDq7X4uVxe7cSgXuqZvyfG6kagTzwj2lfynxOaKQg=="],
|
"@effect/platform-node": ["@effect/platform-node@4.0.0-beta.83", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.83", "mime": "^4.1.0", "undici": "^8.2.0" }, "peerDependencies": { "effect": "^4.0.0-beta.83", "ioredis": "^5.7.0" } }, "sha512-RmpVGu/+X/Bif3/g1Rzj8oFzTOknoVB3yHCa0b179vytPpKe+Kj9ZwKNcAnKWqHUDkbSPBq1Ca60mvOHr2/+LQ=="],
|
||||||
|
|
||||||
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-beta.98", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.0" }, "peerDependencies": { "effect": "^4.0.0-beta.98" } }, "sha512-iySXaffnCJX1sNAIp79ghhIeui9E5qwUQyqd1VLPkB9UNO4vdpd9B5fTEXwe7S/GusL4jsk9vSvX38XJgRFG1w=="],
|
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-beta.83", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.20.0" }, "peerDependencies": { "effect": "^4.0.0-beta.83" } }, "sha512-+yr/+PJmKTgmJq1QOINSBPgLu7Cjc4CZcotBXnGjyDEizOmimFgTkN2B8PBJAKIKUWYWfobjXqC+58/VhhPKAw=="],
|
||||||
|
|
||||||
"@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0-beta.98", "", { "peerDependencies": { "effect": "^4.0.0-beta.98" } }, "sha512-cc41uLhYBqexdbTNu4dlui+31E8hcVLEapLySa0C8d60FmBY8IEAV/RD3oF+6pqPslKEZ9p1+XVLdDm0iflw5Q=="],
|
"@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0-beta.83", "", { "peerDependencies": { "effect": "^4.0.0-beta.83" } }, "sha512-6OaxLsWffxkh9pXYUSyj/AxjVb9URY2rG9U6atjxClWy30Jx77R9Pm3Rrc7cQ63kQurePavEw1bQbzQ/SILiQQ=="],
|
||||||
|
|
||||||
"@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="],
|
"@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="],
|
||||||
|
|
||||||
@@ -2189,8 +2167,6 @@
|
|||||||
|
|
||||||
"@openauthjs/openauth": ["@openauthjs/openauth@0.0.0-20250322224806", "", { "dependencies": { "@standard-schema/spec": "1.0.0-beta.3", "aws4fetch": "1.0.20", "jose": "5.9.6" }, "peerDependencies": { "arctic": "^2.2.2", "hono": "^4.0.0" } }, "sha512-p5IWSRXvABcwocH2dNI0w8c1QJelIOFulwhKk+aLLFfUbs8u1pr7kQbYe8yCSM2+bcLHiwbogpUQc2ovrGwCuw=="],
|
"@openauthjs/openauth": ["@openauthjs/openauth@0.0.0-20250322224806", "", { "dependencies": { "@standard-schema/spec": "1.0.0-beta.3", "aws4fetch": "1.0.20", "jose": "5.9.6" }, "peerDependencies": { "arctic": "^2.2.2", "hono": "^4.0.0" } }, "sha512-p5IWSRXvABcwocH2dNI0w8c1QJelIOFulwhKk+aLLFfUbs8u1pr7kQbYe8yCSM2+bcLHiwbogpUQc2ovrGwCuw=="],
|
||||||
|
|
||||||
"@opencode-ai/ai": ["@opencode-ai/ai@workspace:packages/ai"],
|
|
||||||
|
|
||||||
"@opencode-ai/app": ["@opencode-ai/app@workspace:packages/app"],
|
"@opencode-ai/app": ["@opencode-ai/app@workspace:packages/app"],
|
||||||
|
|
||||||
"@opencode-ai/cli": ["@opencode-ai/cli@workspace:packages/cli"],
|
"@opencode-ai/cli": ["@opencode-ai/cli@workspace:packages/cli"],
|
||||||
@@ -2229,6 +2205,8 @@
|
|||||||
|
|
||||||
"@opencode-ai/httpapi-codegen": ["@opencode-ai/httpapi-codegen@workspace:packages/httpapi-codegen"],
|
"@opencode-ai/httpapi-codegen": ["@opencode-ai/httpapi-codegen@workspace:packages/httpapi-codegen"],
|
||||||
|
|
||||||
|
"@opencode-ai/ai": ["@opencode-ai/ai@workspace:packages/ai"],
|
||||||
|
|
||||||
"@opencode-ai/plugin": ["@opencode-ai/plugin@workspace:packages/plugin"],
|
"@opencode-ai/plugin": ["@opencode-ai/plugin@workspace:packages/plugin"],
|
||||||
|
|
||||||
"@opencode-ai/protocol": ["@opencode-ai/protocol@workspace:packages/protocol"],
|
"@opencode-ai/protocol": ["@opencode-ai/protocol@workspace:packages/protocol"],
|
||||||
@@ -2293,27 +2271,27 @@
|
|||||||
|
|
||||||
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.41.1", "", {}, "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA=="],
|
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.41.1", "", {}, "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA=="],
|
||||||
|
|
||||||
"@opentui/core": ["@opentui/core@0.4.5", "", { "dependencies": { "bun-ffi-structs": "0.2.4", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.4.5", "@opentui/core-darwin-x64": "0.4.5", "@opentui/core-linux-arm64": "0.4.5", "@opentui/core-linux-arm64-musl": "0.4.5", "@opentui/core-linux-x64": "0.4.5", "@opentui/core-linux-x64-musl": "0.4.5", "@opentui/core-win32-arm64": "0.4.5", "@opentui/core-win32-x64": "0.4.5" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-JsgRTPkA6e+Vxmumxai6SElOSlRQkbzNKHlCfemlArRiLhfC1IZ9RXJo2QH4xSu+uBOWAM90uss73/pPlkdEig=="],
|
"@opentui/core": ["@opentui/core@0.4.3", "", { "dependencies": { "bun-ffi-structs": "0.2.4", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.4.3", "@opentui/core-darwin-x64": "0.4.3", "@opentui/core-linux-arm64": "0.4.3", "@opentui/core-linux-arm64-musl": "0.4.3", "@opentui/core-linux-x64": "0.4.3", "@opentui/core-linux-x64-musl": "0.4.3", "@opentui/core-win32-arm64": "0.4.3", "@opentui/core-win32-x64": "0.4.3" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-rrJfAk13tALDqldYjhc78eWQ+aKq1iknJgffIOg3OwyZoqQo+p6gtuqyhmWvXIfQzlNUbpgpCPcxbXlhMnlaHQ=="],
|
||||||
|
|
||||||
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.4.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8KUG0oRidnR+oW1RSZJ72/PhZLl+qRRMk5U/mieF4c0SJ5V3tYACpBZAKzQfHNd1f7QzD8FHZct1lPpQgtmkWg=="],
|
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.4.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-p5+7AAxpxGuDGagyQfewKtmTFnN7THvTVY4FyKqUtJomNaHdQXPHztapNNzMx0DGWbwOUbVKzpL+yc3CZY3chQ=="],
|
||||||
|
|
||||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.4.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-R2bocsg55gwjOqCp/MWFgFYzRmsduKegB6nzgFAPCvAD/L5Jf30xpWJWFlSg3x8vxe1L9WJ84dfqa4M7mZZ3wA=="],
|
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.4.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-+fh0vEUE0lwVC7RW5ijYLRlTLp5NfvCRj8SzxDVd7IL2j2ssB6YXcfIbXq2EW7UGnrejwPRXf1tgUrIXW9KmOw=="],
|
||||||
|
|
||||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.4.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-R4MZ25a4CzOAGVjW9aj1hUfzQGVfCJwrwBDbNs2SXaIvzcZqkxCVtU4FoQ5LsaD0j/BdNQVg2CIfFkFsm1fDuQ=="],
|
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.4.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-gl6qA5QJy6u8Cbt7gOtHbhhfMZ4qQDb0kEwFXHcMGmbnKzz4OHoq74D6tNjyvSQB9saoC7C6C0tvn2DcJOuNog=="],
|
||||||
|
|
||||||
"@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.4.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ieqdyKI6EIYPalYAETB2wsdP83hr5Ifi+dFnBFUmdEEFHsoKwBmn2S7bsTOYlX7Bg03F4/YPIg+IvRpeC+cUJw=="],
|
"@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.4.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-8p8g8/AEq/xFGpQ7XcIFKcAqjc0QwsZcv+Ll9RbCDpUA56FGH6jfLDir0KYTNTgYXJTIrBIENI9K46VuxMUMQA=="],
|
||||||
|
|
||||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.4.5", "", { "os": "linux", "cpu": "x64" }, "sha512-SNyuQoxMKI1vuJhgxSSW96adWM6LqFl2SoS3GM4tGeneGOanVVG2Y06PvlytXvF4cKik97t0rqkVMRetmOs93w=="],
|
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.4.3", "", { "os": "linux", "cpu": "x64" }, "sha512-dXpJitiZdYE3hq2Pvx6e9I0uPQSOcnaLLp1pDgWAHv+3kvKSHEX//9Yr/pV/Ua6qqT7p+2D/K4vXNap/NKVo2w=="],
|
||||||
|
|
||||||
"@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.4.5", "", { "os": "linux", "cpu": "x64" }, "sha512-mKVKcIcPiSVVZZsdPSBoWwoa2/TCeQAaMDeHF7PFw2kt5bTXZPP7xxWfRQLCNIcA1eaGl59UuwUWHDR2Ve548Q=="],
|
"@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.4.3", "", { "os": "linux", "cpu": "x64" }, "sha512-/QiFpCrpU2O7vy8QYmLIQYbvAtKDgmqcVjR7dGtqSzkiQk3ktNJoo5RozG7ueXnjung1Wp0nKldKxo2Csg/OrA=="],
|
||||||
|
|
||||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.4.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-GHTTsqeR45q2Iek9Rb7ty+x/hAKn2jZ1ujlCgPR8LBKyF7h0E1dNFryoZ7ehMc3kJndP1sKn836IemKFqxuDdQ=="],
|
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.4.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-Mx2zuOjrhm/z2SDS6RExIyjP/SnN/8QhhagxURUw0jQi/NssGSeAllu1cBAFFnhobJL5QLTE4FU4CRhUK9svgg=="],
|
||||||
|
|
||||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.4.5", "", { "os": "win32", "cpu": "x64" }, "sha512-Y8T/yXCDGagRGiQrtmuB6AhRcPucKFs/Dre3v8kJwNYqDccI4FzUPKclZ7djfmRZNjl7JUqPhZZP/PwDpQocMg=="],
|
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.4.3", "", { "os": "win32", "cpu": "x64" }, "sha512-NuoqvWKGXaYnmlqvu7Gg2lLI6yVMnS9OfWBvxp+7Q+McSgHFSTQmYBXaPpvQ8HikpQXE1nCeMPtuSG4PdZHe2w=="],
|
||||||
|
|
||||||
"@opentui/keymap": ["@opentui/keymap@0.4.5", "", { "dependencies": { "@opentui/core": "0.4.5" }, "peerDependencies": { "@opentui/react": "0.4.5", "@opentui/solid": "0.4.5", "react": ">=19.2.0", "solid-js": "1.9.12" }, "optionalPeers": ["@opentui/react", "@opentui/solid", "react", "solid-js"] }, "sha512-S1wzKHhF70zT6bH+VBFY+lSeTImLcIFW28JNQiME8MoPcy6KGPs7rKFSHrb/U7P8rsTJeRfW5A4d1Cy6PKodDg=="],
|
"@opentui/keymap": ["@opentui/keymap@0.4.3", "", { "dependencies": { "@opentui/core": "0.4.3" }, "peerDependencies": { "@opentui/react": "0.4.3", "@opentui/solid": "0.4.3", "react": ">=19.2.0", "solid-js": "1.9.12" }, "optionalPeers": ["@opentui/react", "@opentui/solid", "react", "solid-js"] }, "sha512-sinX0pyQBRrEvo89PSSUbSUDIYpL3xWo81VEfec58VFoVRB5FG48/deAtvRTQfJ8w1kgbzN8hzdOXdSm61zBmw=="],
|
||||||
|
|
||||||
"@opentui/solid": ["@opentui/solid@0.4.5", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.4.5", "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-B0RSkXnrtPVfEJOX+Hj+axjLJ3lzbG1BZw5I7Pvb9OPp48Vzg2cW2a3cSa86/q48ndLt647i/XwFPIw/jqnI5g=="],
|
"@opentui/solid": ["@opentui/solid@0.4.3", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.4.3", "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-RcV0+S8HMdXOASyr7HmJUBuTUIaFPzAxMDa44VftS5C2JUgrmAuWo0Njv1q3TWRB1owjHnyKhEfWGKq7A82wxw=="],
|
||||||
|
|
||||||
"@orama/orama": ["@orama/orama@3.1.18", "", {}, "sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA=="],
|
"@orama/orama": ["@orama/orama@3.1.18", "", {}, "sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA=="],
|
||||||
|
|
||||||
@@ -2893,7 +2871,7 @@
|
|||||||
|
|
||||||
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.3.6", "", { "dependencies": { "@smithy/core": "^3.24.5", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-tHhdiWZfG1ZIh2YcRfPJmY2gHcBmqbAzqm3ER4TIDFYsSEqTD5tICT7cgQ/kI8LRakxp12myOYyK68XPn7MnHw=="],
|
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.3.6", "", { "dependencies": { "@smithy/core": "^3.24.5", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-tHhdiWZfG1ZIh2YcRfPJmY2gHcBmqbAzqm3ER4TIDFYsSEqTD5tICT7cgQ/kI8LRakxp12myOYyK68XPn7MnHw=="],
|
||||||
|
|
||||||
"@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.14", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.1", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw=="],
|
"@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.7", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DrpkEoM3j9cBBWhufqBwnbbn+3nf1N9FP6xuVJ+e220jbactKuQgaZwjwP5CP1t+O94brm2JgVMD2atMGX3xIQ=="],
|
||||||
|
|
||||||
"@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.3.5", "", { "dependencies": { "@smithy/core": "^3.24.5", "tslib": "^2.6.2" } }, "sha512-M9rMkTar7JcRrvUHsK1271AuWDmrISIPQpQ4TSHmYZ4KMisGnMH0gfjCWnBwdndR7skvvp/UheHhZGvO3Cr8/g=="],
|
"@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.3.5", "", { "dependencies": { "@smithy/core": "^3.24.5", "tslib": "^2.6.2" } }, "sha512-M9rMkTar7JcRrvUHsK1271AuWDmrISIPQpQ4TSHmYZ4KMisGnMH0gfjCWnBwdndR7skvvp/UheHhZGvO3Cr8/g=="],
|
||||||
|
|
||||||
@@ -2967,7 +2945,7 @@
|
|||||||
|
|
||||||
"@smithy/util-stream": ["@smithy/util-stream@4.6.5", "", { "dependencies": { "@smithy/core": "^3.24.5", "tslib": "^2.6.2" } }, "sha512-PFzBVEBP5k8R+mK/c+VAKmtpUTL+KzBIXWJ6oM0GWOb31K+QgymXV9IW03XLPM1wtkC7oAb9ZBN2aswSSVbNFg=="],
|
"@smithy/util-stream": ["@smithy/util-stream@4.6.5", "", { "dependencies": { "@smithy/core": "^3.24.5", "tslib": "^2.6.2" } }, "sha512-PFzBVEBP5k8R+mK/c+VAKmtpUTL+KzBIXWJ6oM0GWOb31K+QgymXV9IW03XLPM1wtkC7oAb9ZBN2aswSSVbNFg=="],
|
||||||
|
|
||||||
"@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
"@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
|
||||||
|
|
||||||
"@smithy/util-waiter": ["@smithy/util-waiter@4.4.5", "", { "dependencies": { "@smithy/core": "^3.24.5", "tslib": "^2.6.2" } }, "sha512-EYviebytZE6vplW0AGwZ2Rc3sNuVR83lfUCNZu11VchUiKhMwJqrRWy7iVDTNEwG/vEwItno591Iad6/prj6Bw=="],
|
"@smithy/util-waiter": ["@smithy/util-waiter@4.4.5", "", { "dependencies": { "@smithy/core": "^3.24.5", "tslib": "^2.6.2" } }, "sha512-EYviebytZE6vplW0AGwZ2Rc3sNuVR83lfUCNZu11VchUiKhMwJqrRWy7iVDTNEwG/vEwItno591Iad6/prj6Bw=="],
|
||||||
|
|
||||||
@@ -3029,7 +3007,7 @@
|
|||||||
|
|
||||||
"@standard-community/standard-openapi": ["@standard-community/standard-openapi@0.2.9", "", { "peerDependencies": { "@standard-community/standard-json": "^0.3.5", "@standard-schema/spec": "^1.0.0", "arktype": "^2.1.20", "effect": "^3.17.14", "openapi-types": "^12.1.3", "sury": "^10.0.0", "typebox": "^1.0.0", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-openapi": "^4" }, "optionalPeers": ["arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-openapi"] }, "sha512-htj+yldvN1XncyZi4rehbf9kLbu8os2Ke/rfqoZHCMHuw34kiF3LP/yQPdA0tQ940y8nDq3Iou8R3wG+AGGyvg=="],
|
"@standard-community/standard-openapi": ["@standard-community/standard-openapi@0.2.9", "", { "peerDependencies": { "@standard-community/standard-json": "^0.3.5", "@standard-schema/spec": "^1.0.0", "arktype": "^2.1.20", "effect": "^3.17.14", "openapi-types": "^12.1.3", "sury": "^10.0.0", "typebox": "^1.0.0", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-openapi": "^4" }, "optionalPeers": ["arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-openapi"] }, "sha512-htj+yldvN1XncyZi4rehbf9kLbu8os2Ke/rfqoZHCMHuw34kiF3LP/yQPdA0tQ940y8nDq3Iou8R3wG+AGGyvg=="],
|
||||||
|
|
||||||
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
|
||||||
|
|
||||||
"@stoplight/better-ajv-errors": ["@stoplight/better-ajv-errors@1.0.3", "", { "dependencies": { "jsonpointer": "^5.0.0", "leven": "^3.1.0" }, "peerDependencies": { "ajv": ">=8" } }, "sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA=="],
|
"@stoplight/better-ajv-errors": ["@stoplight/better-ajv-errors@1.0.3", "", { "dependencies": { "jsonpointer": "^5.0.0", "leven": "^3.1.0" }, "peerDependencies": { "ajv": ">=8" } }, "sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA=="],
|
||||||
|
|
||||||
@@ -4037,7 +4015,7 @@
|
|||||||
|
|
||||||
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
||||||
|
|
||||||
"effect": ["effect@4.0.0-beta.98", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.9.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.4", "multipasta": "^0.2.8", "toml": "^4.1.2", "uuid": "^14.0.1", "yaml": "^2.9.0" } }, "sha512-oz+bsG5h+6RNrw4t5GMfQrk/xBS8ROoqkYsuvRhBr5O7mCOrpvH/hbw+QrDzvKIpX4HJClwm86F94c87W0sJxg=="],
|
"effect": ["effect@4.0.0-beta.83", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.8.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.1", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^14.0.0", "yaml": "^2.9.0" } }, "sha512-0wsak8RtgGAr9UWSbVDgJHZcUqMSvicHcvaZv1MbMM7MCGgW4Rn/137J1MHQbwYPcwYGxT/IqehFd+UbYuj78w=="],
|
||||||
|
|
||||||
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
||||||
|
|
||||||
@@ -4213,7 +4191,7 @@
|
|||||||
|
|
||||||
"extsprintf": ["extsprintf@1.4.1", "", {}, "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA=="],
|
"extsprintf": ["extsprintf@1.4.1", "", {}, "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA=="],
|
||||||
|
|
||||||
"fast-check": ["fast-check@4.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="],
|
"fast-check": ["fast-check@4.8.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg=="],
|
||||||
|
|
||||||
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
|
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
|
||||||
|
|
||||||
@@ -5077,7 +5055,7 @@
|
|||||||
|
|
||||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
"msgpackr": ["msgpackr@2.0.4", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA=="],
|
"msgpackr": ["msgpackr@2.0.2", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-c5hYOXFbP79Slh6Dzd2wzk+jnV7mX1UxfMYtilnY1NmalXPqG8DGb5cYCMBrW4AsH3zekBBZd4QrKz9NhtvYLQ=="],
|
||||||
|
|
||||||
"msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="],
|
"msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="],
|
||||||
|
|
||||||
@@ -5085,7 +5063,7 @@
|
|||||||
|
|
||||||
"multicast-dns": ["multicast-dns@7.2.5", "", { "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" }, "bin": { "multicast-dns": "cli.js" } }, "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg=="],
|
"multicast-dns": ["multicast-dns@7.2.5", "", { "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" }, "bin": { "multicast-dns": "cli.js" } }, "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg=="],
|
||||||
|
|
||||||
"multipasta": ["multipasta@0.2.8", "", {}, "sha512-ZPWuMKyv0cSO29f7hozp+k6+crZbQijV8ipMvxNxRf2SwtYGTX1ZX89Kd20VV4H9Znonx+EQn+iy1wGQsJ+b+Q=="],
|
"multipasta": ["multipasta@0.2.7", "", {}, "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA=="],
|
||||||
|
|
||||||
"mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="],
|
"mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="],
|
||||||
|
|
||||||
@@ -5615,8 +5593,6 @@
|
|||||||
|
|
||||||
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
|
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
|
||||||
|
|
||||||
"resolve.exports": ["resolve.exports@2.0.3", "", {}, "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A=="],
|
|
||||||
|
|
||||||
"responselike": ["responselike@2.0.1", "", { "dependencies": { "lowercase-keys": "^2.0.0" } }, "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw=="],
|
"responselike": ["responselike@2.0.1", "", { "dependencies": { "lowercase-keys": "^2.0.0" } }, "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw=="],
|
||||||
|
|
||||||
"restore-cursor": ["restore-cursor@4.0.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg=="],
|
"restore-cursor": ["restore-cursor@4.0.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg=="],
|
||||||
@@ -5985,7 +5961,7 @@
|
|||||||
|
|
||||||
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
||||||
|
|
||||||
"toml": ["toml@4.3.0", "", {}, "sha512-lVb8X9BsPVuH0M4BKeS91tXAmJvCjQ5UIyAbQFaxkKGyUFK2RPkhwaFSQH8vbpl1d23eu/IBH+dwVMHWaq9A5A=="],
|
"toml": ["toml@4.1.1", "", {}, "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw=="],
|
||||||
|
|
||||||
"toolbeam-docs-theme": ["toolbeam-docs-theme@0.4.8", "", { "peerDependencies": { "@astrojs/starlight": "^0.34.3", "astro": "^5.7.13" } }, "sha512-b+5ynEFp4Woe5a22hzNQm42lD23t13ZMihVxHbzjA50zdcM9aOSJTIjdJ0PDSd4/50HbBXcpHiQsz6rM4N88ww=="],
|
"toolbeam-docs-theme": ["toolbeam-docs-theme@0.4.8", "", { "peerDependencies": { "@astrojs/starlight": "^0.34.3", "astro": "^5.7.13" } }, "sha512-b+5ynEFp4Woe5a22hzNQm42lD23t13ZMihVxHbzjA50zdcM9aOSJTIjdJ0PDSd4/50HbBXcpHiQsz6rM4N88ww=="],
|
||||||
|
|
||||||
@@ -6071,7 +6047,7 @@
|
|||||||
|
|
||||||
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
|
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
|
||||||
|
|
||||||
"undici": ["undici@8.7.0", "", {}, "sha512-N7iQtfyLhIMOFgQubvmLV26svHpO0bqKnAiWotTQCVKCmWrcGbBotPuW1x+xwYZ2VHdSTVUfPQQnlEt1/LouTQ=="],
|
"undici": ["undici@8.3.0", "", {}, "sha512-TkUDgb6tl7KOGZ+7e8E3d2FYgUQgF6z5YypqjWmixVQSQERFcVrVg0ySADm2LVLRh5ljAaHTCR5Fmz3Q34rB7Q=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||||
|
|
||||||
@@ -6153,7 +6129,7 @@
|
|||||||
|
|
||||||
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
|
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
|
||||||
|
|
||||||
"uuid": ["uuid@14.0.1", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew=="],
|
"uuid": ["uuid@14.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg=="],
|
||||||
|
|
||||||
"valibot": ["valibot@1.4.1", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-klCmFTz2jeDluy9RwX+F884TCiogtdBJ/YaxSx1EOBYXa3NXNWj8kR1jjN8rzluwojJVWWaHJ4r1U5LfICnM3g=="],
|
"valibot": ["valibot@1.4.1", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-klCmFTz2jeDluy9RwX+F884TCiogtdBJ/YaxSx1EOBYXa3NXNWj8kR1jjN8rzluwojJVWWaHJ4r1U5LfICnM3g=="],
|
||||||
|
|
||||||
@@ -6359,6 +6335,10 @@
|
|||||||
|
|
||||||
"@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="],
|
"@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="],
|
||||||
|
|
||||||
|
"@ai-sdk/amazon-bedrock/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.14", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.1", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw=="],
|
||||||
|
|
||||||
|
"@ai-sdk/amazon-bedrock/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
"@ai-sdk/anthropic/@ai-sdk/provider": ["@ai-sdk/provider@3.0.10", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw=="],
|
"@ai-sdk/anthropic/@ai-sdk/provider": ["@ai-sdk/provider@3.0.10", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw=="],
|
||||||
|
|
||||||
"@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="],
|
"@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="],
|
||||||
@@ -6415,6 +6395,8 @@
|
|||||||
|
|
||||||
"@ai-sdk/perplexity/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
"@ai-sdk/perplexity/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
||||||
|
|
||||||
|
"@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"@ai-sdk/togetherai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
"@ai-sdk/togetherai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
||||||
|
|
||||||
"@ai-sdk/vercel/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
"@ai-sdk/vercel/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
||||||
@@ -6475,18 +6457,26 @@
|
|||||||
|
|
||||||
"@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=="],
|
||||||
|
|
||||||
|
"@aws-sdk/client-athena/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
"@aws-sdk/client-cognito-identity/@aws-sdk/core": ["@aws-sdk/core@3.974.15", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@aws-sdk/xml-builder": "^3.972.26", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.5", "@smithy/signature-v4": "^5.4.5", "@smithy/types": "^4.14.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-UpA0rTGW/tHGITcCqHisbuuEPraYg9GG+mWmXjY5+RxZBMLGe6aL9oe0ix50LztwAcPIkGZLH0yWdMIkCM10hw=="],
|
"@aws-sdk/client-cognito-identity/@aws-sdk/core": ["@aws-sdk/core@3.974.15", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@aws-sdk/xml-builder": "^3.972.26", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.5", "@smithy/signature-v4": "^5.4.5", "@smithy/types": "^4.14.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-UpA0rTGW/tHGITcCqHisbuuEPraYg9GG+mWmXjY5+RxZBMLGe6aL9oe0ix50LztwAcPIkGZLH0yWdMIkCM10hw=="],
|
||||||
|
|
||||||
"@aws-sdk/client-cognito-identity/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.47", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.41", "@aws-sdk/credential-provider-http": "^3.972.43", "@aws-sdk/credential-provider-ini": "^3.972.46", "@aws-sdk/credential-provider-process": "^3.972.41", "@aws-sdk/credential-provider-sso": "^3.972.45", "@aws-sdk/credential-provider-web-identity": "^3.972.45", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.5", "@smithy/credential-provider-imds": "^4.3.6", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-HrId+C0DWA5qDIyLG64/kjUB2RNtPypxmABnIctK+TA1P1kHlOYoE/Wf5T5tKOMKgb08P7k/zNyhvfJ3lh5Oag=="],
|
"@aws-sdk/client-cognito-identity/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.47", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.41", "@aws-sdk/credential-provider-http": "^3.972.43", "@aws-sdk/credential-provider-ini": "^3.972.46", "@aws-sdk/credential-provider-process": "^3.972.41", "@aws-sdk/credential-provider-sso": "^3.972.45", "@aws-sdk/credential-provider-web-identity": "^3.972.45", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.5", "@smithy/credential-provider-imds": "^4.3.6", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-HrId+C0DWA5qDIyLG64/kjUB2RNtPypxmABnIctK+TA1P1kHlOYoE/Wf5T5tKOMKgb08P7k/zNyhvfJ3lh5Oag=="],
|
||||||
|
|
||||||
"@aws-sdk/client-cognito-identity/@aws-sdk/types": ["@aws-sdk/types@3.973.9", "", { "dependencies": { "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg=="],
|
"@aws-sdk/client-cognito-identity/@aws-sdk/types": ["@aws-sdk/types@3.973.9", "", { "dependencies": { "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg=="],
|
||||||
|
|
||||||
|
"@aws-sdk/client-firehose/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
"@aws-sdk/client-lambda/@aws-sdk/core": ["@aws-sdk/core@3.974.15", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@aws-sdk/xml-builder": "^3.972.26", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.5", "@smithy/signature-v4": "^5.4.5", "@smithy/types": "^4.14.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-UpA0rTGW/tHGITcCqHisbuuEPraYg9GG+mWmXjY5+RxZBMLGe6aL9oe0ix50LztwAcPIkGZLH0yWdMIkCM10hw=="],
|
"@aws-sdk/client-lambda/@aws-sdk/core": ["@aws-sdk/core@3.974.15", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@aws-sdk/xml-builder": "^3.972.26", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.5", "@smithy/signature-v4": "^5.4.5", "@smithy/types": "^4.14.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-UpA0rTGW/tHGITcCqHisbuuEPraYg9GG+mWmXjY5+RxZBMLGe6aL9oe0ix50LztwAcPIkGZLH0yWdMIkCM10hw=="],
|
||||||
|
|
||||||
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.47", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.41", "@aws-sdk/credential-provider-http": "^3.972.43", "@aws-sdk/credential-provider-ini": "^3.972.46", "@aws-sdk/credential-provider-process": "^3.972.41", "@aws-sdk/credential-provider-sso": "^3.972.45", "@aws-sdk/credential-provider-web-identity": "^3.972.45", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.5", "@smithy/credential-provider-imds": "^4.3.6", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-HrId+C0DWA5qDIyLG64/kjUB2RNtPypxmABnIctK+TA1P1kHlOYoE/Wf5T5tKOMKgb08P7k/zNyhvfJ3lh5Oag=="],
|
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.47", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.41", "@aws-sdk/credential-provider-http": "^3.972.43", "@aws-sdk/credential-provider-ini": "^3.972.46", "@aws-sdk/credential-provider-process": "^3.972.41", "@aws-sdk/credential-provider-sso": "^3.972.45", "@aws-sdk/credential-provider-web-identity": "^3.972.45", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.5", "@smithy/credential-provider-imds": "^4.3.6", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-HrId+C0DWA5qDIyLG64/kjUB2RNtPypxmABnIctK+TA1P1kHlOYoE/Wf5T5tKOMKgb08P7k/zNyhvfJ3lh5Oag=="],
|
||||||
|
|
||||||
"@aws-sdk/client-lambda/@aws-sdk/types": ["@aws-sdk/types@3.973.9", "", { "dependencies": { "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg=="],
|
"@aws-sdk/client-lambda/@aws-sdk/types": ["@aws-sdk/types@3.973.9", "", { "dependencies": { "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg=="],
|
||||||
|
|
||||||
|
"@aws-sdk/client-s3/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
|
"@aws-sdk/client-sso/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
"@aws-sdk/client-sts/@aws-sdk/core": ["@aws-sdk/core@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/core": "^3.2.0", "@smithy/node-config-provider": "^4.0.2", "@smithy/property-provider": "^4.0.2", "@smithy/protocol-http": "^5.1.0", "@smithy/signature-v4": "^5.0.2", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/util-middleware": "^4.0.2", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA=="],
|
"@aws-sdk/client-sts/@aws-sdk/core": ["@aws-sdk/core@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/core": "^3.2.0", "@smithy/node-config-provider": "^4.0.2", "@smithy/property-provider": "^4.0.2", "@smithy/protocol-http": "^5.1.0", "@smithy/signature-v4": "^5.0.2", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/util-middleware": "^4.0.2", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA=="],
|
||||||
|
|
||||||
"@aws-sdk/client-sts/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.782.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.775.0", "@aws-sdk/credential-provider-http": "3.775.0", "@aws-sdk/credential-provider-ini": "3.782.0", "@aws-sdk/credential-provider-process": "3.775.0", "@aws-sdk/credential-provider-sso": "3.782.0", "@aws-sdk/credential-provider-web-identity": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/credential-provider-imds": "^4.0.2", "@smithy/property-provider": "^4.0.2", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-HZiAF+TCEyKjju9dgysjiPIWgt/+VerGaeEp18mvKLNfgKz1d+/82A2USEpNKTze7v3cMFASx3CvL8yYyF7mJw=="],
|
"@aws-sdk/client-sts/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.782.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.775.0", "@aws-sdk/credential-provider-http": "3.775.0", "@aws-sdk/credential-provider-ini": "3.782.0", "@aws-sdk/credential-provider-process": "3.775.0", "@aws-sdk/credential-provider-sso": "3.782.0", "@aws-sdk/credential-provider-web-identity": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/credential-provider-imds": "^4.0.2", "@smithy/property-provider": "^4.0.2", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-HZiAF+TCEyKjju9dgysjiPIWgt/+VerGaeEp18mvKLNfgKz1d+/82A2USEpNKTze7v3cMFASx3CvL8yYyF7mJw=="],
|
||||||
@@ -6509,6 +6499,10 @@
|
|||||||
|
|
||||||
"@aws-sdk/client-sts/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.782.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/node-config-provider": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dMFkUBgh2Bxuw8fYZQoH/u3H4afQ12VSkzEi//qFiDTwbKYq+u+RYjc8GLDM6JSK1BShMu5AVR7HD4ap1TYUnA=="],
|
"@aws-sdk/client-sts/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.782.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/types": "3.775.0", "@smithy/node-config-provider": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dMFkUBgh2Bxuw8fYZQoH/u3H4afQ12VSkzEi//qFiDTwbKYq+u+RYjc8GLDM6JSK1BShMu5AVR7HD4ap1TYUnA=="],
|
||||||
|
|
||||||
|
"@aws-sdk/client-sts/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
|
"@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
"@aws-sdk/credential-provider-cognito-identity/@aws-sdk/types": ["@aws-sdk/types@3.973.9", "", { "dependencies": { "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg=="],
|
"@aws-sdk/credential-provider-cognito-identity/@aws-sdk/types": ["@aws-sdk/types@3.973.9", "", { "dependencies": { "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg=="],
|
||||||
|
|
||||||
"@aws-sdk/credential-provider-env/@aws-sdk/core": ["@aws-sdk/core@3.974.15", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@aws-sdk/xml-builder": "^3.972.26", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.5", "@smithy/signature-v4": "^5.4.5", "@smithy/types": "^4.14.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-UpA0rTGW/tHGITcCqHisbuuEPraYg9GG+mWmXjY5+RxZBMLGe6aL9oe0ix50LztwAcPIkGZLH0yWdMIkCM10hw=="],
|
"@aws-sdk/credential-provider-env/@aws-sdk/core": ["@aws-sdk/core@3.974.15", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@aws-sdk/xml-builder": "^3.972.26", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.5", "@smithy/signature-v4": "^5.4.5", "@smithy/types": "^4.14.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-UpA0rTGW/tHGITcCqHisbuuEPraYg9GG+mWmXjY5+RxZBMLGe6aL9oe0ix50LztwAcPIkGZLH0yWdMIkCM10hw=="],
|
||||||
@@ -6557,6 +6551,10 @@
|
|||||||
|
|
||||||
"@aws-sdk/credential-providers/@aws-sdk/types": ["@aws-sdk/types@3.973.9", "", { "dependencies": { "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg=="],
|
"@aws-sdk/credential-providers/@aws-sdk/types": ["@aws-sdk/types@3.973.9", "", { "dependencies": { "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg=="],
|
||||||
|
|
||||||
|
"@aws-sdk/middleware-flexible-checksums/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
|
"@aws-sdk/middleware-sdk-s3/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
"@aws-sdk/nested-clients/@aws-sdk/core": ["@aws-sdk/core@3.974.15", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@aws-sdk/xml-builder": "^3.972.26", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.5", "@smithy/signature-v4": "^5.4.5", "@smithy/types": "^4.14.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-UpA0rTGW/tHGITcCqHisbuuEPraYg9GG+mWmXjY5+RxZBMLGe6aL9oe0ix50LztwAcPIkGZLH0yWdMIkCM10hw=="],
|
"@aws-sdk/nested-clients/@aws-sdk/core": ["@aws-sdk/core@3.974.15", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@aws-sdk/xml-builder": "^3.972.26", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.5", "@smithy/signature-v4": "^5.4.5", "@smithy/types": "^4.14.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-UpA0rTGW/tHGITcCqHisbuuEPraYg9GG+mWmXjY5+RxZBMLGe6aL9oe0ix50LztwAcPIkGZLH0yWdMIkCM10hw=="],
|
||||||
|
|
||||||
"@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.30", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@smithy/signature-v4": "^5.4.5", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-HULDLMVzkmTSEv6//7kx2kRevp/VYUpm8hJNNFbmhxDn0fUiGTxVcM9yg31TukvTq8nyOBDUN2gH0o5IRbKjdw=="],
|
"@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.30", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@smithy/signature-v4": "^5.4.5", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-HULDLMVzkmTSEv6//7kx2kRevp/VYUpm8hJNNFbmhxDn0fUiGTxVcM9yg31TukvTq8nyOBDUN2gH0o5IRbKjdw=="],
|
||||||
@@ -6631,8 +6629,6 @@
|
|||||||
|
|
||||||
"@hey-api/openapi-ts/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
"@hey-api/openapi-ts/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
||||||
|
|
||||||
"@hono/standard-validator/@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
|
|
||||||
|
|
||||||
"@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
"@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
||||||
|
|
||||||
"@inquirer/core/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
|
"@inquirer/core/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
|
||||||
@@ -6853,10 +6849,6 @@
|
|||||||
|
|
||||||
"@opencode-ai/cli/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
"@opencode-ai/cli/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
||||||
|
|
||||||
"@opencode-ai/console-app/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.7", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DrpkEoM3j9cBBWhufqBwnbbn+3nf1N9FP6xuVJ+e220jbactKuQgaZwjwP5CP1t+O94brm2JgVMD2atMGX3xIQ=="],
|
|
||||||
|
|
||||||
"@opencode-ai/console-app/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
|
|
||||||
|
|
||||||
"@opencode-ai/console-mail/@types/react": ["@types/react@18.0.25", "", { "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, "sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g=="],
|
"@opencode-ai/console-mail/@types/react": ["@types/react@18.0.25", "", { "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, "sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g=="],
|
||||||
|
|
||||||
"@opencode-ai/core/@ai-sdk/openai": ["@ai-sdk/openai@3.0.84", "", { "dependencies": { "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cmgbeJL0bbY0yTJH4/AdmP5E7MjWRL9G8UdhIi0JlV/So03o82ORJofW8OzwCZPTORVQblFbpZXYGDcUd9NdUQ=="],
|
"@opencode-ai/core/@ai-sdk/openai": ["@ai-sdk/openai@3.0.84", "", { "dependencies": { "@ai-sdk/provider": "3.0.14", "@ai-sdk/provider-utils": "4.0.38" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cmgbeJL0bbY0yTJH4/AdmP5E7MjWRL9G8UdhIi0JlV/So03o82ORJofW8OzwCZPTORVQblFbpZXYGDcUd9NdUQ=="],
|
||||||
@@ -6871,6 +6863,10 @@
|
|||||||
|
|
||||||
"@opencode-ai/desktop/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
|
"@opencode-ai/desktop/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
|
||||||
|
|
||||||
|
"@opencode-ai/ai/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.14", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.1", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw=="],
|
||||||
|
|
||||||
|
"@opencode-ai/ai/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
"@opencode-ai/script/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
"@opencode-ai/script/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
|
|
||||||
"@opencode-ai/session-ui/@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="],
|
"@opencode-ai/session-ui/@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="],
|
||||||
@@ -7355,6 +7351,8 @@
|
|||||||
|
|
||||||
"editorconfig/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="],
|
"editorconfig/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="],
|
||||||
|
|
||||||
|
"effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"electron-builder/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
"electron-builder/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||||
|
|
||||||
"electron-builder/yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
"electron-builder/yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
||||||
@@ -7415,6 +7413,8 @@
|
|||||||
|
|
||||||
"fumadocs-core/shiki": ["shiki@4.3.1", "", { "dependencies": { "@shikijs/core": "4.3.1", "@shikijs/engine-javascript": "4.3.1", "@shikijs/engine-oniguruma": "4.3.1", "@shikijs/langs": "4.3.1", "@shikijs/themes": "4.3.1", "@shikijs/types": "4.3.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw=="],
|
"fumadocs-core/shiki": ["shiki@4.3.1", "", { "dependencies": { "@shikijs/core": "4.3.1", "@shikijs/engine-javascript": "4.3.1", "@shikijs/engine-oniguruma": "4.3.1", "@shikijs/langs": "4.3.1", "@shikijs/themes": "4.3.1", "@shikijs/types": "4.3.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw=="],
|
||||||
|
|
||||||
|
"fumadocs-mdx/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"fumadocs-mdx/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
|
"fumadocs-mdx/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
|
||||||
|
|
||||||
"fumadocs-mdx/esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="],
|
"fumadocs-mdx/esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="],
|
||||||
@@ -7553,8 +7553,6 @@
|
|||||||
|
|
||||||
"opencode/@solid-primitives/scheduled": ["@solid-primitives/scheduled@1.5.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-/j2igE0xyNaHhj6kMfcUQn5rAVSTLbAX+CDEBm25hSNBmNiHLu2lM7Usj2kJJ5j36D67bE8wR1hBNA8hjtvsQA=="],
|
"opencode/@solid-primitives/scheduled": ["@solid-primitives/scheduled@1.5.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-/j2igE0xyNaHhj6kMfcUQn5rAVSTLbAX+CDEBm25hSNBmNiHLu2lM7Usj2kJJ5j36D67bE8wR1hBNA8hjtvsQA=="],
|
||||||
|
|
||||||
"opencode/@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
|
|
||||||
|
|
||||||
"opencode/minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="],
|
"opencode/minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="],
|
||||||
|
|
||||||
"opencode/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
"opencode/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
@@ -7761,6 +7759,46 @@
|
|||||||
|
|
||||||
"@actions/github/@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
|
"@actions/github/@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
|
||||||
|
|
||||||
|
"@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/anthropic/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/azure/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/cerebras/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/cohere/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/deepgram/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/deepinfra/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/deepseek/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/elevenlabs/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/fireworks/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/google-vertex/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/google/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/groq/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/mistral/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/openai-compatible/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/openai/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/perplexity/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/togetherai/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/vercel/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"@ai-sdk/xai/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"@astrojs/check/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
|
"@astrojs/check/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
|
||||||
|
|
||||||
"@astrojs/check/yargs/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=="],
|
"@astrojs/check/yargs/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=="],
|
||||||
@@ -8363,25 +8401,9 @@
|
|||||||
|
|
||||||
"@solidjs/start/shiki/@shikijs/types": ["@shikijs/types@1.29.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw=="],
|
"@solidjs/start/shiki/@shikijs/types": ["@shikijs/types@1.29.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw=="],
|
||||||
|
|
||||||
"@standard-community/standard-json/effect/fast-check": ["fast-check@4.8.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg=="],
|
"@standard-community/standard-json/effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"@standard-community/standard-json/effect/msgpackr": ["msgpackr@2.0.2", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-c5hYOXFbP79Slh6Dzd2wzk+jnV7mX1UxfMYtilnY1NmalXPqG8DGb5cYCMBrW4AsH3zekBBZd4QrKz9NhtvYLQ=="],
|
"@standard-community/standard-openapi/effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"@standard-community/standard-json/effect/multipasta": ["multipasta@0.2.7", "", {}, "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA=="],
|
|
||||||
|
|
||||||
"@standard-community/standard-json/effect/toml": ["toml@4.1.1", "", {}, "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw=="],
|
|
||||||
|
|
||||||
"@standard-community/standard-json/effect/uuid": ["uuid@14.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg=="],
|
|
||||||
|
|
||||||
"@standard-community/standard-openapi/effect/fast-check": ["fast-check@4.8.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg=="],
|
|
||||||
|
|
||||||
"@standard-community/standard-openapi/effect/msgpackr": ["msgpackr@2.0.2", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-c5hYOXFbP79Slh6Dzd2wzk+jnV7mX1UxfMYtilnY1NmalXPqG8DGb5cYCMBrW4AsH3zekBBZd4QrKz9NhtvYLQ=="],
|
|
||||||
|
|
||||||
"@standard-community/standard-openapi/effect/multipasta": ["multipasta@0.2.7", "", {}, "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA=="],
|
|
||||||
|
|
||||||
"@standard-community/standard-openapi/effect/toml": ["toml@4.1.1", "", {}, "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw=="],
|
|
||||||
|
|
||||||
"@standard-community/standard-openapi/effect/uuid": ["uuid@14.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg=="],
|
|
||||||
|
|
||||||
"@stoplight/spectral-core/minimatch/brace-expansion": ["brace-expansion@1.1.15", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg=="],
|
"@stoplight/spectral-core/minimatch/brace-expansion": ["brace-expansion@1.1.15", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg=="],
|
||||||
|
|
||||||
@@ -8457,6 +8479,10 @@
|
|||||||
|
|
||||||
"ai-gateway-provider/@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="],
|
"ai-gateway-provider/@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="],
|
||||||
|
|
||||||
|
"ai-gateway-provider/@ai-sdk/amazon-bedrock/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.14", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.1", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw=="],
|
||||||
|
|
||||||
|
"ai-gateway-provider/@ai-sdk/amazon-bedrock/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
"ai-gateway-provider/@ai-sdk/anthropic/@ai-sdk/provider": ["@ai-sdk/provider@3.0.10", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw=="],
|
"ai-gateway-provider/@ai-sdk/anthropic/@ai-sdk/provider": ["@ai-sdk/provider@3.0.10", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw=="],
|
||||||
|
|
||||||
"ai-gateway-provider/@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="],
|
"ai-gateway-provider/@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="],
|
||||||
@@ -8847,6 +8873,10 @@
|
|||||||
|
|
||||||
"venice-ai-sdk-provider/@ai-sdk/provider-utils/@ai-sdk/provider": ["@ai-sdk/provider@3.0.12", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-sj9DWTJ2Ze0WR9qsiOPqoqzNx3OxL6iMxHImbhvoe9qOspekbzxNDMiJ4TIGfYHYh9w4OmBjz3prvqhzTi96+Q=="],
|
"venice-ai-sdk-provider/@ai-sdk/provider-utils/@ai-sdk/provider": ["@ai-sdk/provider@3.0.12", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-sj9DWTJ2Ze0WR9qsiOPqoqzNx3OxL6iMxHImbhvoe9qOspekbzxNDMiJ4TIGfYHYh9w4OmBjz3prvqhzTi96+Q=="],
|
||||||
|
|
||||||
|
"venice-ai-sdk-provider/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"vitest/@vitest/expect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"vitest/@vitest/expect/chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="],
|
"vitest/@vitest/expect/chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="],
|
||||||
|
|
||||||
"wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="],
|
"wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="],
|
||||||
@@ -8959,8 +8989,12 @@
|
|||||||
|
|
||||||
"@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="],
|
"@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="],
|
||||||
|
|
||||||
|
"@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
"@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.933.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.932.0", "@aws-sdk/middleware-host-header": "3.930.0", "@aws-sdk/middleware-logger": "3.930.0", "@aws-sdk/middleware-recursion-detection": "3.933.0", "@aws-sdk/middleware-user-agent": "3.932.0", "@aws-sdk/region-config-resolver": "3.930.0", "@aws-sdk/types": "3.930.0", "@aws-sdk/util-endpoints": "3.930.0", "@aws-sdk/util-user-agent-browser": "3.930.0", "@aws-sdk/util-user-agent-node": "3.932.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.2", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.9", "@smithy/middleware-retry": "^4.4.9", "@smithy/middleware-serde": "^4.2.5", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.5", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.8", "@smithy/util-defaults-mode-node": "^4.2.11", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-o1GX0+IPlFi/D8ei9y/jj3yucJWNfPnbB5appVBWevAyUdZA5KzQ2nK/hDxiu9olTZlFEFpf1m1Rn3FaGxHqsw=="],
|
"@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.933.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.932.0", "@aws-sdk/middleware-host-header": "3.930.0", "@aws-sdk/middleware-logger": "3.930.0", "@aws-sdk/middleware-recursion-detection": "3.933.0", "@aws-sdk/middleware-user-agent": "3.932.0", "@aws-sdk/region-config-resolver": "3.930.0", "@aws-sdk/types": "3.930.0", "@aws-sdk/util-endpoints": "3.930.0", "@aws-sdk/util-user-agent-browser": "3.930.0", "@aws-sdk/util-user-agent-node": "3.932.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.2", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.9", "@smithy/middleware-retry": "^4.4.9", "@smithy/middleware-serde": "^4.2.5", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.5", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.8", "@smithy/util-defaults-mode-node": "^4.2.11", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-o1GX0+IPlFi/D8ei9y/jj3yucJWNfPnbB5appVBWevAyUdZA5KzQ2nK/hDxiu9olTZlFEFpf1m1Rn3FaGxHqsw=="],
|
||||||
|
|
||||||
|
"@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
"@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="],
|
"@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="],
|
||||||
|
|
||||||
"@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="],
|
"@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="],
|
||||||
@@ -9111,6 +9145,8 @@
|
|||||||
|
|
||||||
"@octokit/rest/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
|
"@octokit/rest/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
|
||||||
|
|
||||||
|
"@opencode-ai/core/@ai-sdk/openai/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"@opencode-ai/desktop/@actions/artifact/@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
|
"@opencode-ai/desktop/@actions/artifact/@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
|
||||||
|
|
||||||
"@opencode-ai/www/@cloudflare/vite-plugin/@cloudflare/unenv-preset/workerd": ["workerd@1.20260708.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260708.1", "@cloudflare/workerd-darwin-arm64": "1.20260708.1", "@cloudflare/workerd-linux-64": "1.20260708.1", "@cloudflare/workerd-linux-arm64": "1.20260708.1", "@cloudflare/workerd-windows-64": "1.20260708.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-WAK+Kt/VVCSldH2qSr8lx46XCJ4Q+bdlHNaFqUtOHthBEIB8C1N8HVW+VOLrxDoTCk0NGNv0zajnBeQK4JOB9w=="],
|
"@opencode-ai/www/@cloudflare/vite-plugin/@cloudflare/unenv-preset/workerd": ["workerd@1.20260708.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260708.1", "@cloudflare/workerd-darwin-arm64": "1.20260708.1", "@cloudflare/workerd-linux-64": "1.20260708.1", "@cloudflare/workerd-linux-arm64": "1.20260708.1", "@cloudflare/workerd-windows-64": "1.20260708.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-WAK+Kt/VVCSldH2qSr8lx46XCJ4Q+bdlHNaFqUtOHthBEIB8C1N8HVW+VOLrxDoTCk0NGNv0zajnBeQK4JOB9w=="],
|
||||||
@@ -9293,6 +9329,14 @@
|
|||||||
|
|
||||||
"@vitejs/plugin-react/vite/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
|
"@vitejs/plugin-react/vite/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
|
||||||
|
|
||||||
|
"ai-gateway-provider/@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"ai-gateway-provider/@ai-sdk/anthropic/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"ai-gateway-provider/@ai-sdk/azure/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
|
"ai-gateway-provider/@ai-sdk/deepseek/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
"ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
"app-builder-lib/@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="],
|
"app-builder-lib/@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="],
|
||||||
@@ -9435,6 +9479,8 @@
|
|||||||
|
|
||||||
"@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.3.0", "", {}, "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q=="],
|
"@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.3.0", "", {}, "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q=="],
|
||||||
|
|
||||||
|
"@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
|
||||||
|
|
||||||
"@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.3.0", "", {}, "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q=="],
|
"@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.3.0", "", {}, "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q=="],
|
||||||
|
|
||||||
"@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.3.0", "", {}, "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q=="],
|
"@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.3.0", "", {}, "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q=="],
|
||||||
|
|||||||
+8
-11
@@ -37,18 +37,18 @@
|
|||||||
"packages/slack"
|
"packages/slack"
|
||||||
],
|
],
|
||||||
"catalog": {
|
"catalog": {
|
||||||
"@effect/opentelemetry": "4.0.0-beta.98",
|
"@effect/opentelemetry": "4.0.0-beta.83",
|
||||||
"@effect/platform-node": "4.0.0-beta.98",
|
"@effect/platform-node": "4.0.0-beta.83",
|
||||||
"@effect/sql-sqlite-bun": "4.0.0-beta.98",
|
"@effect/sql-sqlite-bun": "4.0.0-beta.83",
|
||||||
"@npmcli/arborist": "9.4.0",
|
"@npmcli/arborist": "9.4.0",
|
||||||
"@types/bun": "1.3.13",
|
"@types/bun": "1.3.13",
|
||||||
"@types/cross-spawn": "6.0.6",
|
"@types/cross-spawn": "6.0.6",
|
||||||
"@octokit/rest": "22.0.0",
|
"@octokit/rest": "22.0.0",
|
||||||
"@hono/standard-validator": "0.2.0",
|
"@hono/standard-validator": "0.2.0",
|
||||||
"@hono/zod-validator": "0.4.2",
|
"@hono/zod-validator": "0.4.2",
|
||||||
"@opentui/core": "0.4.5",
|
"@opentui/core": "0.4.3",
|
||||||
"@opentui/keymap": "0.4.5",
|
"@opentui/keymap": "0.4.3",
|
||||||
"@opentui/solid": "0.4.5",
|
"@opentui/solid": "0.4.3",
|
||||||
"@tanstack/solid-virtual": "3.13.32",
|
"@tanstack/solid-virtual": "3.13.32",
|
||||||
"@shikijs/stream": "4.2.0",
|
"@shikijs/stream": "4.2.0",
|
||||||
"ulid": "3.0.1",
|
"ulid": "3.0.1",
|
||||||
@@ -69,13 +69,12 @@
|
|||||||
"dompurify": "3.3.1",
|
"dompurify": "3.3.1",
|
||||||
"drizzle-kit": "1.0.0-rc.2",
|
"drizzle-kit": "1.0.0-rc.2",
|
||||||
"drizzle-orm": "1.0.0-rc.2",
|
"drizzle-orm": "1.0.0-rc.2",
|
||||||
"effect": "4.0.0-beta.98",
|
"effect": "4.0.0-beta.83",
|
||||||
"ai": "6.0.168",
|
"ai": "6.0.168",
|
||||||
"cross-spawn": "7.0.6",
|
"cross-spawn": "7.0.6",
|
||||||
"hono": "4.10.7",
|
"hono": "4.10.7",
|
||||||
"hono-openapi": "1.1.2",
|
"hono-openapi": "1.1.2",
|
||||||
"fuzzysort": "3.1.0",
|
"fuzzysort": "3.1.0",
|
||||||
"get-east-asian-width": "1.6.0",
|
|
||||||
"luxon": "3.6.1",
|
"luxon": "3.6.1",
|
||||||
"marked": "17.0.6",
|
"marked": "17.0.6",
|
||||||
"marked-shiki": "1.2.1",
|
"marked-shiki": "1.2.1",
|
||||||
@@ -86,11 +85,9 @@
|
|||||||
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
||||||
"zod": "4.1.8",
|
"zod": "4.1.8",
|
||||||
"remeda": "2.26.0",
|
"remeda": "2.26.0",
|
||||||
"resolve.exports": "2.0.3",
|
|
||||||
"sst": "4.13.1",
|
"sst": "4.13.1",
|
||||||
"shiki": "4.2.0",
|
"shiki": "4.2.0",
|
||||||
"solid-list": "0.3.0",
|
"solid-list": "0.3.0",
|
||||||
"string-width": "7.2.0",
|
|
||||||
"tailwindcss": "4.1.11",
|
"tailwindcss": "4.1.11",
|
||||||
"vite": "7.1.4",
|
"vite": "7.1.4",
|
||||||
"@solidjs/meta": "0.29.4",
|
"@solidjs/meta": "0.29.4",
|
||||||
@@ -166,7 +163,7 @@
|
|||||||
"@ai-sdk/google@3.0.73": "patches/@ai-sdk%2Fgoogle@3.0.73.patch",
|
"@ai-sdk/google@3.0.73": "patches/@ai-sdk%2Fgoogle@3.0.73.patch",
|
||||||
"@pierre/trees@1.0.0-beta.4": "patches/@pierre%2Ftrees@1.0.0-beta.4.patch",
|
"@pierre/trees@1.0.0-beta.4": "patches/@pierre%2Ftrees@1.0.0-beta.4.patch",
|
||||||
"@modelcontextprotocol/sdk@1.29.0": "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch",
|
"@modelcontextprotocol/sdk@1.29.0": "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch",
|
||||||
"effect@4.0.0-beta.98": "patches/effect@4.0.0-beta.98.patch",
|
"effect@4.0.0-beta.83": "patches/effect@4.0.0-beta.83.patch",
|
||||||
"@tanstack/virtual-core@3.17.3": "patches/@tanstack%2Fvirtual-core@3.17.3.patch"
|
"@tanstack/virtual-core@3.17.3": "patches/@tanstack%2Fvirtual-core@3.17.3.patch"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-19
@@ -127,37 +127,23 @@ OpenAI Chat and OpenAI Responses are separate semantic entrypoints:
|
|||||||
- `@opencode-ai/ai/providers/openai/responses`
|
- `@opencode-ai/ai/providers/openai/responses`
|
||||||
- `@opencode-ai/ai/providers/openai-compatible/responses`
|
- `@opencode-ai/ai/providers/openai-compatible/responses`
|
||||||
- `@opencode-ai/ai/providers/anthropic-compatible`
|
- `@opencode-ai/ai/providers/anthropic-compatible`
|
||||||
- `@opencode-ai/ai/providers/google-vertex/gemini`
|
- `@opencode-ai/ai/providers/google-vertex`
|
||||||
- `@opencode-ai/ai/providers/google-vertex/chat`
|
- `@opencode-ai/ai/providers/google-vertex/anthropic`
|
||||||
- `@opencode-ai/ai/providers/google-vertex/responses`
|
|
||||||
- `@opencode-ai/ai/providers/google-vertex/messages`
|
|
||||||
|
|
||||||
Responses HTTP versus WebSocket is a scoped `transport` setting on the OpenAI Responses entrypoint, not another entrypoint. Azure follows the same Chat/Responses split at `providers/azure/chat` and `providers/azure/responses`. Generic OpenAI-compatible Chat remains at `providers/openai-compatible`; compatible Responses is separate at `providers/openai-compatible/responses`. Generic Anthropic Messages-compatible providers use `providers/anthropic-compatible`, which the named Anthropic provider composes. Google Gemini and Amazon Bedrock expose their single native API through their existing provider paths.
|
Responses HTTP versus WebSocket is a scoped `transport` setting on the OpenAI Responses entrypoint, not another entrypoint. Azure follows the same Chat/Responses split at `providers/azure/chat` and `providers/azure/responses`. Generic OpenAI-compatible Chat remains at `providers/openai-compatible`; compatible Responses is separate at `providers/openai-compatible/responses`. Generic Anthropic Messages-compatible providers use `providers/anthropic-compatible`, which the named Anthropic provider composes. Google Gemini and Amazon Bedrock expose their single native API through their existing provider paths.
|
||||||
|
|
||||||
Vertex Gemini, Vertex Chat, Vertex Responses, and Vertex Messages are separate API entrypoints. All accept `project`, `location`, and an optional `accessToken`; when no explicit token or auth override is supplied they lazily use Google Application Default Credentials. Vertex Gemini instead selects express mode when `apiKey` or `GOOGLE_VERTEX_API_KEY` is present. Vertex Chat targets MaaS models through the OpenAI-compatible Chat Completions endpoint, while Vertex Responses targets Grok models and defaults `store` to `false` as required by Vertex. `providers/google-vertex` remains the default alias for `providers/google-vertex/gemini`.
|
Vertex Gemini and Vertex Anthropic are separate products with separate entrypoints. Both accept `project`, `location`, and an optional `accessToken`; when no explicit token or auth override is supplied they lazily use Google Application Default Credentials. Vertex Gemini instead selects express mode when `apiKey` or `GOOGLE_VERTEX_API_KEY` is present.
|
||||||
|
|
||||||
Tuned Vertex Gemini deployments use model ids shaped like `endpoints/1234567890` and require OAuth or ADC; Vertex express-mode API keys support publisher models only.
|
Tuned Vertex Gemini deployments use model ids shaped like `endpoints/1234567890` and require OAuth or ADC; Vertex express-mode API keys support publisher models only.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { model } from "@opencode-ai/ai/providers/google-vertex/gemini"
|
import { model } from "@opencode-ai/ai/providers/google-vertex"
|
||||||
|
|
||||||
model("gemini-3.5-flash", { project: "my-project", location: "global" })
|
model("gemini-3.5-flash", { project: "my-project", location: "global" })
|
||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { model } from "@opencode-ai/ai/providers/google-vertex/chat"
|
import { model } from "@opencode-ai/ai/providers/google-vertex/anthropic"
|
||||||
|
|
||||||
model("deepseek-ai/deepseek-v3.2-maas", { project: "my-project", location: "global" })
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { model } from "@opencode-ai/ai/providers/google-vertex/responses"
|
|
||||||
|
|
||||||
model("xai/grok-4.20-reasoning", { project: "my-project", location: "global" })
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { model } from "@opencode-ai/ai/providers/google-vertex/messages"
|
|
||||||
|
|
||||||
model("claude-sonnet-4-6", { project: "my-project", location: "global" })
|
model("claude-sonnet-4-6", { project: "my-project", location: "global" })
|
||||||
```
|
```
|
||||||
|
|||||||
+16
-18
@@ -1,13 +1,13 @@
|
|||||||
# LLM Provider Parity Status
|
# LLM Provider Parity Status
|
||||||
|
|
||||||
Last reviewed: 2026-07-16
|
Last reviewed: 2026-07-15
|
||||||
|
|
||||||
This file tracks the gap between the native `@opencode-ai/ai` package and the AI SDK provider packages that opencode still depends on for many catalog/runtime paths.
|
This file tracks the gap between the native `@opencode-ai/ai` package and the AI SDK provider packages that opencode still depends on for many catalog/runtime paths.
|
||||||
|
|
||||||
## Existing Status Sources
|
## Existing Status Sources
|
||||||
|
|
||||||
| File | What it tracks | Limitation |
|
| File | What it tracks | Limitation |
|
||||||
| ----------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------- |
|
| ------------------------------------ | -------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
||||||
| `packages/ai/DESIGN.md` | Future clean-break API proposal for `@opencode-ai/ai`. | Not a provider parity tracker. |
|
| `packages/ai/DESIGN.md` | Future clean-break API proposal for `@opencode-ai/ai`. | Not a provider parity tracker. |
|
||||||
| `packages/ai/example/call-sites.md` | Route/value/provider-facade migration checklist and call-site sketches. | Architecture migration only; not AI SDK package parity. |
|
| `packages/ai/example/call-sites.md` | Route/value/provider-facade migration checklist and call-site sketches. | Architecture migration only; not AI SDK package parity. |
|
||||||
|
|
||||||
@@ -23,10 +23,8 @@ This file tracks the gap between the native `@opencode-ai/ai` package and the AI
|
|||||||
| Anthropic-compatible Messages | `src/protocols/anthropic-messages.ts`, `src/providers/anthropic-compatible.ts` | Usable for deployments that implement the Anthropic Messages wire protocol. Named Anthropic composes this base. | No named compatible family profiles or recorded deployment coverage yet. |
|
| Anthropic-compatible Messages | `src/protocols/anthropic-messages.ts`, `src/providers/anthropic-compatible.ts` | Usable for deployments that implement the Anthropic Messages wire protocol. Named Anthropic composes this base. | No named compatible family profiles or recorded deployment coverage yet. |
|
||||||
| Anthropic Messages | `src/protocols/anthropic-messages.ts`, `src/providers/anthropic.ts` | Usable. Supports tools, thinking, cache control, images, server-hosted tool events, and usage. | Provider option surface is small. Beta/header handling, metadata, and newer Messages fields need a typed parity pass. |
|
| Anthropic Messages | `src/protocols/anthropic-messages.ts`, `src/providers/anthropic.ts` | Usable. Supports tools, thinking, cache control, images, server-hosted tool events, and usage. | Provider option surface is small. Beta/header handling, metadata, and newer Messages fields need a typed parity pass. |
|
||||||
| Gemini Developer API | `src/protocols/gemini.ts`, `src/providers/google.ts` | Usable for Google API key flow. Supports text, images, tools, thinking signatures, and cache usage. | This is not Vertex. Typed provider options are narrow; many Gemini request fields currently require raw `http.body` overlays. |
|
| Gemini Developer API | `src/protocols/gemini.ts`, `src/providers/google.ts` | Usable for Google API key flow. Supports text, images, tools, thinking signatures, and cache usage. | This is not Vertex. Typed provider options are narrow; many Gemini request fields currently require raw `http.body` overlays. |
|
||||||
| Vertex Gemini | `src/protocols/gemini.ts`, `src/providers/google-vertex.ts` | Usable through API-key express mode, explicit OAuth tokens, or ADC with project/location endpoint derivation, including tuned `endpoints/...` deployments. | Core runner/catalog mapping and recorded provider coverage are missing. |
|
| Vertex Gemini | `src/protocols/google-vertex-gemini.ts`, `src/providers/google-vertex.ts` | Usable through API-key express mode, explicit OAuth tokens, or ADC with project/location endpoint derivation, including tuned `endpoints/...` deployments. | Core runner/catalog mapping and recorded provider coverage are missing. |
|
||||||
| Vertex Chat | `src/protocols/openai-chat.ts`, `src/providers/google-vertex-chat.ts` | Usable for MaaS models through OpenAI-compatible Chat Completions with explicit OAuth tokens or ADC and project/location endpoint derivation. | Core runner/catalog mapping and recorded provider coverage are missing; MaaS family-specific request parity needs review. |
|
| Vertex Anthropic Messages | `src/protocols/google-vertex-anthropic.ts`, `src/providers/google-vertex-anthropic.ts` | Usable through explicit OAuth tokens or ADC, including global, regional, and `eu`/`us` multi-region endpoints. | Core runner/catalog mapping and recorded provider coverage are missing; Vertex-specific hosted-tool parity needs review. |
|
||||||
| Vertex Responses | `src/protocols/openai-responses.ts`, `src/providers/google-vertex-responses.ts` | Usable for Grok models through OpenAI-compatible Responses with explicit OAuth tokens or ADC, project/location endpoint derivation, and storage disabled by default. | Core runner/catalog mapping and recorded provider coverage are missing; stateful continuation is not supported by Vertex. |
|
|
||||||
| Vertex Messages | `src/protocols/anthropic-messages.ts`, `src/providers/google-vertex-messages.ts` | Usable through explicit OAuth tokens or ADC, including global, regional, and `eu`/`us` multi-region endpoints. | Core runner/catalog mapping and recorded provider coverage are missing; Vertex-specific hosted-tool parity needs review. |
|
|
||||||
| Bedrock Converse | `src/protocols/bedrock-converse.ts`, `src/providers/amazon-bedrock.ts` | Partial but real. Supports AWS event-stream framing, SigV4 with supplied credentials, bearer auth, tools, reasoning signatures, media, cache points, and recorded tests. | Native facade does not mirror the AI SDK plugin's default AWS credential chain/profile behavior. Runner/catalog mapping is missing. Guardrails, inference profiles, region-specific model ID fixes, and model-specific request fields need a parity pass. |
|
| Bedrock Converse | `src/protocols/bedrock-converse.ts`, `src/providers/amazon-bedrock.ts` | Partial but real. Supports AWS event-stream framing, SigV4 with supplied credentials, bearer auth, tools, reasoning signatures, media, cache points, and recorded tests. | Native facade does not mirror the AI SDK plugin's default AWS credential chain/profile behavior. Runner/catalog mapping is missing. Guardrails, inference profiles, region-specific model ID fixes, and model-specific request fields need a parity pass. |
|
||||||
| Azure OpenAI | `src/providers/azure.ts` using OpenAI Chat/Responses protocols | Partial. Supports resource/base URL setup, API key auth, API version query, Chat, and Responses selectors. | Core runner does not map `@ai-sdk/azure` to this native facade. AAD/token auth and Azure-specific endpoint variants need review. |
|
| Azure OpenAI | `src/providers/azure.ts` using OpenAI Chat/Responses protocols | Partial. Supports resource/base URL setup, API key auth, API version query, Chat, and Responses selectors. | Core runner does not map `@ai-sdk/azure` to this native facade. AAD/token auth and Azure-specific endpoint variants need review. |
|
||||||
| Cloudflare AI Gateway / Workers AI | `src/providers/cloudflare.ts` | Present via OpenAI-compatible Chat routes. | Useful but not part of the critical AI SDK replacement set yet. Needs per-product recorded coverage before relying on it broadly. |
|
| Cloudflare AI Gateway / Workers AI | `src/providers/cloudflare.ts` | Present via OpenAI-compatible Chat routes. | Useful but not part of the critical AI SDK replacement set yet. Needs per-product recorded coverage before relying on it broadly. |
|
||||||
@@ -56,8 +54,8 @@ Other `aisdk:` packages, including Google Vertex, Azure, and Bedrock, currently
|
|||||||
| `@ai-sdk/google` | Gemini Developer API | Partial / usable | Add typed options for safety, response schema/modalities, cached content, grounding/search/code execution, and non-text output modes where supported. |
|
| `@ai-sdk/google` | Gemini Developer API | Partial / usable | Add typed options for safety, response schema/modalities, cached content, grounding/search/code execution, and non-text output modes where supported. |
|
||||||
| `@ai-sdk/google-vertex` | Vertex Gemini namespace/facade | Partial / usable | Add runner/catalog mapping, recorded coverage, and broader provider-option parity. |
|
| `@ai-sdk/google-vertex` | Vertex Gemini namespace/facade | Partial / usable | Add runner/catalog mapping, recorded coverage, and broader provider-option parity. |
|
||||||
| `@ai-sdk/google-vertex/anthropic` | Anthropic Messages over Vertex namespace/facade | Partial / usable | Add runner/catalog mapping, recorded coverage, and Vertex-specific hosted-tool parity. |
|
| `@ai-sdk/google-vertex/anthropic` | Anthropic Messages over Vertex namespace/facade | Partial / usable | Add runner/catalog mapping, recorded coverage, and Vertex-specific hosted-tool parity. |
|
||||||
| `@ai-sdk/google-vertex/maas` | Vertex Chat | Partial / usable | Add runner/catalog mapping, recorded coverage, and MaaS family-specific request parity. |
|
| `@ai-sdk/google-vertex/maas` | Vertex MaaS OpenAI-compatible namespace/facade | Missing | Decide native Chat/Responses selection, endpoint derivation, auth, and catalog mapping. |
|
||||||
| `@ai-sdk/google-vertex/xai` | Vertex Chat / Responses | Partial / usable | Decide Chat/Responses selection for catalog models, add runner mapping and recorded coverage, and review xAI-specific request options. |
|
| `@ai-sdk/google-vertex/xai` | Vertex xAI OpenAI-compatible namespace/facade | Missing | Decide whether this composes the generic compatible bases or the xAI facade, then add endpoint/auth mapping and tests. |
|
||||||
| `@ai-sdk/azure` | Azure OpenAI Chat/Responses facade | Partial | Map runner/catalog metadata to native Azure, handle resourceName/baseURL/apiVersion variants, add AAD/token auth story, and verify Chat vs Responses deployment selection. |
|
| `@ai-sdk/azure` | Azure OpenAI Chat/Responses facade | Partial | Map runner/catalog metadata to native Azure, handle resourceName/baseURL/apiVersion variants, add AAD/token auth story, and verify Chat vs Responses deployment selection. |
|
||||||
| `@ai-sdk/amazon-bedrock` | Bedrock Converse | Partial | Add default AWS credential chain/profile support, region/inference-profile model ID handling, provider option parity via `additionalModelRequestFields`, guardrails/performance config, and runner/catalog mapping. |
|
| `@ai-sdk/amazon-bedrock` | Bedrock Converse | Partial | Add default AWS credential chain/profile support, region/inference-profile model ID handling, provider option parity via `additionalModelRequestFields`, guardrails/performance config, and runner/catalog mapping. |
|
||||||
| `@ai-sdk/amazon-bedrock/mantle` | Bedrock Mantle OpenAI-compatible Chat/Responses namespace | Missing | Decide native Mantle shape, likely separate from Converse because it uses OpenAI-compatible Chat/Responses semantics over Bedrock. Add package mapping and tests. |
|
| `@ai-sdk/amazon-bedrock/mantle` | Bedrock Mantle OpenAI-compatible Chat/Responses namespace | Missing | Decide native Mantle shape, likely separate from Converse because it uses OpenAI-compatible Chat/Responses semantics over Bedrock. Add package mapping and tests. |
|
||||||
@@ -67,11 +65,11 @@ Other `aisdk:` packages, including Google Vertex, Azure, and Bedrock, currently
|
|||||||
1. Runner support is narrower than the LLM package. The package has native provider facades for Google, Azure, and Bedrock, but the V2 Session runner only maps OpenAI, Anthropic, and explicit OpenAI-compatible Chat from `aisdk` catalog metadata.
|
1. Runner support is narrower than the LLM package. The package has native provider facades for Google, Azure, and Bedrock, but the V2 Session runner only maps OpenAI, Anthropic, and explicit OpenAI-compatible Chat from `aisdk` catalog metadata.
|
||||||
2. OpenAI-compatible Responses is available as a separate package entrypoint, but the V2 runner still maps `@ai-sdk/openai-compatible` to Chat only. Catalog selection must become API-aware before Responses deployments can use it.
|
2. OpenAI-compatible Responses is available as a separate package entrypoint, but the V2 runner still maps `@ai-sdk/openai-compatible` to Chat only. Catalog selection must become API-aware before Responses deployments can use it.
|
||||||
3. Bedrock native auth is not AI SDK parity. The AI SDK plugin uses the default AWS provider chain, profile, container credentials, and Bedrock bearer token env behavior. Native Bedrock currently expects explicit credentials or bearer auth on the facade.
|
3. Bedrock native auth is not AI SDK parity. The AI SDK plugin uses the default AWS provider chain, profile, container credentials, and Bedrock bearer token env behavior. Native Bedrock currently expects explicit credentials or bearer auth on the facade.
|
||||||
4. Vertex Gemini, Vertex Chat, Vertex Responses, and Vertex Messages now have native package entrypoints, but the core runner does not map catalog metadata to them yet and recorded provider coverage is still missing.
|
4. Vertex Gemini and Vertex Anthropic now have native package entrypoints, but the core runner does not map catalog metadata to them yet and recorded provider coverage is still missing.
|
||||||
5. Azure is only a provider facade, not a full runtime replacement. Native Azure exists, but the catalog runner does not select it, and token auth/resource variants need review.
|
5. Azure is only a provider facade, not a full runtime replacement. Native Azure exists, but the catalog runner does not select it, and token auth/resource variants need review.
|
||||||
6. Provider option typing is uneven. OpenAI, Anthropic, Gemini, Bedrock, and OpenRouter each expose a small typed subset plus raw HTTP overlays; this is useful but not equivalent to AI SDK provider option coverage.
|
6. Provider option typing is uneven. OpenAI, Anthropic, Gemini, Bedrock, and OpenRouter each expose a small typed subset plus raw HTTP overlays; this is useful but not equivalent to AI SDK provider option coverage.
|
||||||
7. Structured output is not provider-native yet. `LLM.generateObject` still uses a synthetic tool strategy, while the future design expects native structured output where reliable and tool fallback where needed.
|
7. Structured output is not provider-native yet. `LLM.generateObject` still uses a synthetic tool strategy, while the future design expects native structured output where reliable and tool fallback where needed.
|
||||||
8. Package/namespace boundaries for the current native loading set are explicit in docs and exports. Other exported provider facades are not catalog package entrypoints until they implement the contract. Vertex xAI still needs catalog API selection; the missing native boundary is Bedrock Mantle.
|
8. Package/namespace boundaries for the current native loading set are explicit in docs and exports. Other exported provider facades are not catalog package entrypoints until they implement the contract. Missing native boundaries remain for Vertex MaaS, Vertex xAI, and Bedrock Mantle.
|
||||||
9. Recorded coverage is uneven. OpenAI, Anthropic, Gemini, Bedrock Converse, Cloudflare, OpenRouter, and several OpenAI-compatible Chat providers have cassettes. Azure, Vertex, and Mantle need first-class recorded scenarios before switching defaults.
|
9. Recorded coverage is uneven. OpenAI, Anthropic, Gemini, Bedrock Converse, Cloudflare, OpenRouter, and several OpenAI-compatible Chat providers have cassettes. Azure, Vertex, and Mantle need first-class recorded scenarios before switching defaults.
|
||||||
|
|
||||||
## Native Namespace Shape
|
## Native Namespace Shape
|
||||||
@@ -79,7 +77,7 @@ Other `aisdk:` packages, including Google Vertex, Azure, and Bedrock, currently
|
|||||||
These are implementation/API slices, not separate npm packages.
|
These are implementation/API slices, not separate npm packages.
|
||||||
|
|
||||||
| API slice | Package-like entrypoint | Purpose |
|
| API slice | Package-like entrypoint | Purpose |
|
||||||
| ----------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
| ----------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
||||||
| OpenAI Chat | `@opencode-ai/ai/providers/openai/chat` | OpenAI `/chat/completions` semantics. |
|
| OpenAI Chat | `@opencode-ai/ai/providers/openai/chat` | OpenAI `/chat/completions` semantics. |
|
||||||
| OpenAI Responses | `@opencode-ai/ai/providers/openai/responses` | OpenAI `/responses` semantics with HTTP/WebSocket selected through settings. |
|
| OpenAI Responses | `@opencode-ai/ai/providers/openai/responses` | OpenAI `/responses` semantics with HTTP/WebSocket selected through settings. |
|
||||||
| OpenAI-compatible Chat | `@opencode-ai/ai/providers/openai-compatible` | Generic OpenAI-compatible `/chat/completions`. |
|
| OpenAI-compatible Chat | `@opencode-ai/ai/providers/openai-compatible` | Generic OpenAI-compatible `/chat/completions`. |
|
||||||
@@ -87,10 +85,10 @@ These are implementation/API slices, not separate npm packages.
|
|||||||
| Anthropic-compatible Messages | `@opencode-ai/ai/providers/anthropic-compatible` | Generic Anthropic-compatible `/messages`. |
|
| Anthropic-compatible Messages | `@opencode-ai/ai/providers/anthropic-compatible` | Generic Anthropic-compatible `/messages`. |
|
||||||
| Anthropic Messages | `@opencode-ai/ai/providers/anthropic` | Anthropic Messages API. |
|
| Anthropic Messages | `@opencode-ai/ai/providers/anthropic` | Anthropic Messages API. |
|
||||||
| Gemini Developer API | `@opencode-ai/ai/providers/google` | Google AI Studio Gemini API. |
|
| Gemini Developer API | `@opencode-ai/ai/providers/google` | Google AI Studio Gemini API. |
|
||||||
| Vertex Gemini | `@opencode-ai/ai/providers/google-vertex/gemini` | Vertex Gemini API; `providers/google-vertex` is the default alias. |
|
| Vertex Gemini | `@opencode-ai/ai/providers/google-vertex` | Vertex Gemini API. |
|
||||||
| Vertex Chat | `@opencode-ai/ai/providers/google-vertex/chat` | Vertex OpenAI-compatible Chat Completions for MaaS models. |
|
| Vertex Anthropic Messages | `@opencode-ai/ai/providers/google-vertex/anthropic` | Vertex-hosted Anthropic Messages API. |
|
||||||
| Vertex Responses | `@opencode-ai/ai/providers/google-vertex/responses` | Vertex OpenAI-compatible Responses for Grok models. |
|
| Vertex MaaS | Missing | Vertex OpenAI-compatible MaaS APIs. |
|
||||||
| Vertex Messages | `@opencode-ai/ai/providers/google-vertex/messages` | Vertex-hosted Anthropic Messages API. |
|
| Vertex xAI | Missing | Vertex-hosted xAI APIs. |
|
||||||
| Bedrock Converse | `@opencode-ai/ai/providers/amazon-bedrock` | AWS Bedrock Converse API. |
|
| Bedrock Converse | `@opencode-ai/ai/providers/amazon-bedrock` | AWS Bedrock Converse API. |
|
||||||
| Bedrock Mantle | Missing | AWS Bedrock Mantle OpenAI-compatible APIs. |
|
| Bedrock Mantle | Missing | AWS Bedrock Mantle OpenAI-compatible APIs. |
|
||||||
| Azure OpenAI Chat | `@opencode-ai/ai/providers/azure/chat` | Azure specialization of OpenAI Chat. |
|
| Azure OpenAI Chat | `@opencode-ai/ai/providers/azure/chat` | Azure specialization of OpenAI Chat. |
|
||||||
@@ -101,8 +99,8 @@ These are implementation/API slices, not separate npm packages.
|
|||||||
1. Add native runner/catalog mappings for `@ai-sdk/azure`, `@ai-sdk/google`, and `@ai-sdk/amazon-bedrock` where the existing native facades are already close.
|
1. Add native runner/catalog mappings for `@ai-sdk/azure`, `@ai-sdk/google`, and `@ai-sdk/amazon-bedrock` where the existing native facades are already close.
|
||||||
2. Add API-aware runner/catalog selection between OpenAI-compatible Chat and Responses.
|
2. Add API-aware runner/catalog selection between OpenAI-compatible Chat and Responses.
|
||||||
3. Bring Bedrock native auth/config to AI SDK parity: region, profile, default AWS credential chain, bearer token env, endpoint override, and cross-region inference profile handling.
|
3. Bring Bedrock native auth/config to AI SDK parity: region, profile, default AWS credential chain, bearer token env, endpoint override, and cross-region inference profile handling.
|
||||||
4. Add runner/catalog mappings and recorded scenarios for the native Vertex Gemini, Chat, Responses, and Messages entrypoints.
|
4. Add runner/catalog mappings and recorded scenarios for the native Vertex Gemini and Vertex Anthropic entrypoints.
|
||||||
5. Decide Chat/Responses selection for `@ai-sdk/google-vertex/xai` catalog models.
|
5. Add native Vertex MaaS and Vertex xAI entrypoints by composing the compatible bases and shared Vertex auth/endpoint setup.
|
||||||
6. Add Bedrock Mantle as a separate OpenAI-compatible Bedrock namespace after deciding whether it uses Chat, Responses, or both by model.
|
6. Add Bedrock Mantle as a separate OpenAI-compatible Bedrock namespace after deciding whether it uses Chat, Responses, or both by model.
|
||||||
7. Expand typed provider options from the existing V1 lowerer knowledge in `packages/core/src/v1/config/provider-options.ts` before adding more raw overlay examples.
|
7. Expand typed provider options from the existing V1 lowerer knowledge in `packages/core/src/v1/config/provider-options.ts` before adding more raw overlay examples.
|
||||||
8. Add recorded provider tests for Azure, Vertex Gemini, Vertex Chat, Vertex Responses, Vertex Messages, Bedrock credential-chain behavior, and Mantle before making native runtime the default for those packages.
|
8. Add recorded provider tests for Azure, Vertex Gemini, Vertex Anthropic, Bedrock credential-chain behavior, and Mantle before making native runtime the default for those packages.
|
||||||
|
|||||||
@@ -360,29 +360,17 @@ import { model } from "@opencode-ai/ai/providers/openai/responses"
|
|||||||
model("gpt-4o", { apiKey, transport: "websocket" })
|
model("gpt-4o", { apiKey, transport: "websocket" })
|
||||||
```
|
```
|
||||||
|
|
||||||
Vertex keeps Gemini, Chat, Responses, and Messages as separate package-like entrypoints,
|
Vertex keeps Gemini and Anthropic Messages as separate package-like entrypoints,
|
||||||
while sharing project/location resolution and ADC authentication internally:
|
while sharing project/location resolution and ADC authentication internally:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { model } from "@opencode-ai/ai/providers/google-vertex/gemini"
|
import { model } from "@opencode-ai/ai/providers/google-vertex"
|
||||||
|
|
||||||
model("gemini-3.5-flash", { project, location: "global" })
|
model("gemini-3.5-flash", { project, location: "global" })
|
||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { model } from "@opencode-ai/ai/providers/google-vertex/chat"
|
import { model } from "@opencode-ai/ai/providers/google-vertex/anthropic"
|
||||||
|
|
||||||
model("deepseek-ai/deepseek-v3.2-maas", { project, location: "global" })
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { model } from "@opencode-ai/ai/providers/google-vertex/responses"
|
|
||||||
|
|
||||||
model("xai/grok-4.20-reasoning", { project, location: "global" })
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { model } from "@opencode-ai/ai/providers/google-vertex/messages"
|
|
||||||
|
|
||||||
model("claude-sonnet-4-6", { project, location: "global" })
|
model("claude-sonnet-4-6", { project, location: "global" })
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { Effect, Schema, Struct } from "effect"
|
||||||
|
import { AnthropicMessages } from "./anthropic-messages"
|
||||||
|
import { Auth } from "../route/auth"
|
||||||
|
import { Route } from "../route/client"
|
||||||
|
import { Endpoint } from "../route/endpoint"
|
||||||
|
import { Framing } from "../route/framing"
|
||||||
|
import { Protocol } from "../route/protocol"
|
||||||
|
|
||||||
|
const VERSION = "vertex-2023-10-16" as const
|
||||||
|
|
||||||
|
export const GoogleVertexAnthropicBody = Schema.Struct({
|
||||||
|
...Struct.omit(AnthropicMessages.AnthropicMessagesBody.fields, ["model"]),
|
||||||
|
anthropic_version: Schema.Literal(VERSION),
|
||||||
|
})
|
||||||
|
export type GoogleVertexAnthropicBody = Schema.Schema.Type<typeof GoogleVertexAnthropicBody>
|
||||||
|
|
||||||
|
export const protocol = Protocol.make({
|
||||||
|
id: "google-vertex-anthropic",
|
||||||
|
body: {
|
||||||
|
schema: GoogleVertexAnthropicBody,
|
||||||
|
from: (request) =>
|
||||||
|
AnthropicMessages.protocol.body.from(request).pipe(
|
||||||
|
Effect.map((body) => ({
|
||||||
|
...Struct.omit(body, ["model"]),
|
||||||
|
anthropic_version: VERSION,
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
stream: AnthropicMessages.protocol.stream,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const route = Route.make({
|
||||||
|
id: "google-vertex-anthropic",
|
||||||
|
provider: "google-vertex-anthropic",
|
||||||
|
providerMetadataKey: "anthropic",
|
||||||
|
protocol,
|
||||||
|
endpoint: Endpoint.path(({ request }) => `/${request.model.id}:streamRawPredict`),
|
||||||
|
auth: Auth.none,
|
||||||
|
framing: Framing.sse,
|
||||||
|
})
|
||||||
|
|
||||||
|
export * as GoogleVertexAnthropic from "./google-vertex-anthropic"
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { Gemini } from "./gemini"
|
||||||
|
import { Auth } from "../route/auth"
|
||||||
|
import { Route } from "../route/client"
|
||||||
|
import { Endpoint } from "../route/endpoint"
|
||||||
|
import { Framing } from "../route/framing"
|
||||||
|
|
||||||
|
export const route = Route.make({
|
||||||
|
id: "google-vertex-gemini",
|
||||||
|
provider: "google-vertex",
|
||||||
|
providerMetadataKey: "google",
|
||||||
|
protocol: Gemini.protocol,
|
||||||
|
endpoint: Endpoint.path(({ request }) => {
|
||||||
|
const model = String(request.model.id)
|
||||||
|
return `/${model.startsWith("endpoints/") ? model : `models/${model}`}:streamGenerateContent?alt=sse`
|
||||||
|
}),
|
||||||
|
auth: Auth.none,
|
||||||
|
framing: Framing.sse,
|
||||||
|
})
|
||||||
|
|
||||||
|
export * as GoogleVertexGemini from "./google-vertex-gemini"
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
export * as AnthropicMessages from "./anthropic-messages"
|
export * as AnthropicMessages from "./anthropic-messages"
|
||||||
|
export * as GoogleVertexAnthropic from "./google-vertex-anthropic"
|
||||||
|
export * as GoogleVertexGemini from "./google-vertex-gemini"
|
||||||
export * as BedrockConverse from "./bedrock-converse"
|
export * as BedrockConverse from "./bedrock-converse"
|
||||||
export * as Gemini from "./gemini"
|
export * as Gemini from "./gemini"
|
||||||
export * as OpenAIChat from "./openai-chat"
|
export * as OpenAIChat from "./openai-chat"
|
||||||
|
|||||||
@@ -878,10 +878,18 @@ const onOutputItemDone = Effect.fn("OpenAIResponses.onOutputItemDone")(function*
|
|||||||
return [state, NO_EVENTS] satisfies StepResult
|
return [state, NO_EVENTS] satisfies StepResult
|
||||||
})
|
})
|
||||||
|
|
||||||
const onResponseFinish = (state: ParserState, event: OpenAIResponsesEvent): StepResult => {
|
const onResponseFinish = Effect.fn("OpenAIResponses.onResponseFinish")(function* (
|
||||||
const events: LLMEvent[] = []
|
state: ParserState,
|
||||||
|
event: OpenAIResponsesEvent,
|
||||||
|
) {
|
||||||
|
const pending =
|
||||||
|
event.type === "response.completed"
|
||||||
|
? yield* ToolStream.finishAll(ADAPTER, state.tools)
|
||||||
|
: { tools: state.tools, events: NO_EVENTS }
|
||||||
|
const events = [...pending.events]
|
||||||
|
const hasFunctionCall = state.hasFunctionCall || pending.events.some(LLMEvent.is.toolCall)
|
||||||
const lifecycle = Lifecycle.finish(state.lifecycle, events, {
|
const lifecycle = Lifecycle.finish(state.lifecycle, events, {
|
||||||
reason: mapFinishReason(event, state.hasFunctionCall),
|
reason: mapFinishReason(event, hasFunctionCall),
|
||||||
usage: mapUsage(event.response?.usage),
|
usage: mapUsage(event.response?.usage),
|
||||||
providerMetadata:
|
providerMetadata:
|
||||||
event.response?.id || event.response?.service_tier
|
event.response?.id || event.response?.service_tier
|
||||||
@@ -891,8 +899,8 @@ const onResponseFinish = (state: ParserState, event: OpenAIResponsesEvent): Step
|
|||||||
})
|
})
|
||||||
: undefined,
|
: undefined,
|
||||||
})
|
})
|
||||||
return [{ ...state, lifecycle }, events]
|
return [{ ...state, tools: pending.tools, hasFunctionCall, lifecycle }, events] satisfies StepResult
|
||||||
}
|
})
|
||||||
|
|
||||||
// Build a single human-readable message from whatever the provider supplied.
|
// Build a single human-readable message from whatever the provider supplied.
|
||||||
// When both code and message are present, prefix the code so consumers see
|
// When both code and message are present, prefix the code so consumers see
|
||||||
@@ -939,8 +947,9 @@ const step = (state: ParserState, event: OpenAIResponsesEvent) => {
|
|||||||
if (event.type === "response.output_item.added") return Effect.succeed(onOutputItemAdded(state, event))
|
if (event.type === "response.output_item.added") return Effect.succeed(onOutputItemAdded(state, event))
|
||||||
if (event.type === "response.function_call_arguments.delta") return onFunctionCallArgumentsDelta(state, event)
|
if (event.type === "response.function_call_arguments.delta") return onFunctionCallArgumentsDelta(state, event)
|
||||||
if (event.type === "response.output_item.done") return onOutputItemDone(state, event)
|
if (event.type === "response.output_item.done") return onOutputItemDone(state, event)
|
||||||
if (event.type === "response.completed" || event.type === "response.incomplete")
|
if (event.type === "response.incomplete" && Object.keys(state.tools).length > 0)
|
||||||
return Effect.succeed(onResponseFinish(state, event))
|
return ProviderShared.eventError(ADAPTER, "OpenAI Responses response incomplete with pending tool calls")
|
||||||
|
if (event.type === "response.completed" || event.type === "response.incomplete") return onResponseFinish(state, event)
|
||||||
if (event.type === "response.failed") return providerError(event, "OpenAI Responses response failed")
|
if (event.type === "response.failed") return providerError(event, "OpenAI Responses response failed")
|
||||||
if (event.type === "error") return providerError(event, "OpenAI Responses stream error")
|
if (event.type === "error") return providerError(event, "OpenAI Responses stream error")
|
||||||
return Effect.succeed<StepResult>([state, NO_EVENTS])
|
return Effect.succeed<StepResult>([state, NO_EVENTS])
|
||||||
|
|||||||
+7
-12
@@ -1,10 +1,10 @@
|
|||||||
import type { ProviderPackage } from "../provider-package"
|
import type { ProviderPackage } from "../provider-package"
|
||||||
import { OpenAICompatibleResponses } from "../protocols/openai-compatible-responses"
|
import { GoogleVertexAnthropic } from "../protocols/google-vertex-anthropic"
|
||||||
import type { RouteDefaultsInput } from "../route/client"
|
import type { RouteDefaultsInput } from "../route/client"
|
||||||
import { ProviderID, type ModelID, type ProviderOptions } from "../schema"
|
import { ProviderID, type ModelID, type ProviderOptions } from "../schema"
|
||||||
import { GoogleVertexShared } from "./google-vertex-shared"
|
import { GoogleVertexShared } from "./google-vertex-shared"
|
||||||
|
|
||||||
export const id = ProviderID.make("google-vertex")
|
export const id = ProviderID.make("google-vertex-anthropic")
|
||||||
|
|
||||||
export type Config = RouteDefaultsInput &
|
export type Config = RouteDefaultsInput &
|
||||||
GoogleVertexShared.OAuthOptions & {
|
GoogleVertexShared.OAuthOptions & {
|
||||||
@@ -22,16 +22,11 @@ export interface Settings extends ProviderPackage.Settings {
|
|||||||
readonly providerOptions?: ProviderOptions
|
readonly providerOptions?: ProviderOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
const route = OpenAICompatibleResponses.route.with({
|
export const routes = [GoogleVertexAnthropic.route]
|
||||||
id: "google-vertex-responses",
|
|
||||||
provider: id,
|
|
||||||
})
|
|
||||||
|
|
||||||
export const routes = [route]
|
|
||||||
|
|
||||||
const configuredRoute = (input: Config) => {
|
const configuredRoute = (input: Config) => {
|
||||||
if ("apiKey" in input && input.apiKey !== undefined)
|
if ("apiKey" in input && input.apiKey !== undefined)
|
||||||
throw new Error("Google Vertex Responses does not support API keys")
|
throw new Error("Google Vertex Anthropic does not support API keys")
|
||||||
const {
|
const {
|
||||||
accessToken: _accessToken,
|
accessToken: _accessToken,
|
||||||
auth: _auth,
|
auth: _auth,
|
||||||
@@ -42,12 +37,12 @@ const configuredRoute = (input: Config) => {
|
|||||||
} = input
|
} = input
|
||||||
const location = GoogleVertexShared.location(inputLocation, "global")
|
const location = GoogleVertexShared.location(inputLocation, "global")
|
||||||
const project = GoogleVertexShared.project(inputProject)
|
const project = GoogleVertexShared.project(inputProject)
|
||||||
return route.with({
|
return GoogleVertexAnthropic.route.with({
|
||||||
...rest,
|
...rest,
|
||||||
endpoint: {
|
endpoint: {
|
||||||
baseURL:
|
baseURL:
|
||||||
baseURL ??
|
baseURL ??
|
||||||
`https://aiplatform.googleapis.com/v1/projects/${GoogleVertexShared.requireProject(project)}/locations/${location}/endpoints/openapi`,
|
`https://${GoogleVertexShared.host(location)}/v1/projects/${GoogleVertexShared.requireProject(project)}/locations/${location}/publishers/anthropic/models`,
|
||||||
},
|
},
|
||||||
auth: GoogleVertexShared.oauth(input, project),
|
auth: GoogleVertexShared.oauth(input, project),
|
||||||
})
|
})
|
||||||
@@ -68,7 +63,7 @@ export const provider = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const model: ProviderPackage.Definition<Settings>["model"] = (modelID, settings) => {
|
export const model: ProviderPackage.Definition<Settings>["model"] = (modelID, settings) => {
|
||||||
if (settings.apiKey !== undefined) throw new Error("Google Vertex Responses does not support API keys")
|
if (settings.apiKey !== undefined) throw new Error("Google Vertex Anthropic does not support API keys")
|
||||||
return configure({
|
return configure({
|
||||||
accessToken: settings.accessToken,
|
accessToken: settings.accessToken,
|
||||||
baseURL: settings.baseURL,
|
baseURL: settings.baseURL,
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
import type { ProviderPackage } from "../provider-package"
|
|
||||||
import { OpenAICompatibleChat } from "../protocols/openai-compatible-chat"
|
|
||||||
import type { RouteDefaultsInput } from "../route/client"
|
|
||||||
import { ProviderID, type ModelID, type ProviderOptions } from "../schema"
|
|
||||||
import { GoogleVertexShared } from "./google-vertex-shared"
|
|
||||||
|
|
||||||
export const id = ProviderID.make("google-vertex")
|
|
||||||
|
|
||||||
export type Config = RouteDefaultsInput &
|
|
||||||
GoogleVertexShared.OAuthOptions & {
|
|
||||||
readonly baseURL?: string
|
|
||||||
readonly location?: string
|
|
||||||
readonly project?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Settings extends ProviderPackage.Settings {
|
|
||||||
readonly accessToken?: string
|
|
||||||
readonly apiKey?: never
|
|
||||||
readonly baseURL?: string
|
|
||||||
readonly location?: string
|
|
||||||
readonly project?: string
|
|
||||||
readonly providerOptions?: ProviderOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
const route = OpenAICompatibleChat.route.with({
|
|
||||||
id: "google-vertex-chat",
|
|
||||||
provider: id,
|
|
||||||
})
|
|
||||||
|
|
||||||
export const routes = [route]
|
|
||||||
|
|
||||||
const configuredRoute = (input: Config) => {
|
|
||||||
if ("apiKey" in input && input.apiKey !== undefined) throw new Error("Google Vertex Chat does not support API keys")
|
|
||||||
const {
|
|
||||||
accessToken: _accessToken,
|
|
||||||
auth: _auth,
|
|
||||||
baseURL,
|
|
||||||
location: inputLocation,
|
|
||||||
project: inputProject,
|
|
||||||
...rest
|
|
||||||
} = input
|
|
||||||
const location = GoogleVertexShared.location(inputLocation, "global")
|
|
||||||
const project = GoogleVertexShared.project(inputProject)
|
|
||||||
return route.with({
|
|
||||||
...rest,
|
|
||||||
endpoint: {
|
|
||||||
baseURL:
|
|
||||||
baseURL ??
|
|
||||||
`https://aiplatform.googleapis.com/v1/projects/${GoogleVertexShared.requireProject(project)}/locations/${location}/endpoints/openapi`,
|
|
||||||
},
|
|
||||||
auth: GoogleVertexShared.oauth(input, project),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const configure = (input: Config = {}) => {
|
|
||||||
const route = configuredRoute(input)
|
|
||||||
return {
|
|
||||||
id,
|
|
||||||
model: (modelID: string | ModelID) => route.model({ id: modelID }),
|
|
||||||
configure,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const provider = {
|
|
||||||
id,
|
|
||||||
configure,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const model: ProviderPackage.Definition<Settings>["model"] = (modelID, settings) => {
|
|
||||||
if (settings.apiKey !== undefined) throw new Error("Google Vertex Chat does not support API keys")
|
|
||||||
return configure({
|
|
||||||
accessToken: settings.accessToken,
|
|
||||||
baseURL: settings.baseURL,
|
|
||||||
headers: settings.headers === undefined ? undefined : { ...settings.headers },
|
|
||||||
http: settings.body === undefined ? undefined : { body: { ...settings.body } },
|
|
||||||
limits: settings.limits,
|
|
||||||
location: settings.location,
|
|
||||||
project: settings.project,
|
|
||||||
providerOptions: settings.providerOptions,
|
|
||||||
}).model(modelID)
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
import { Effect, Schema, Struct } from "effect"
|
|
||||||
import type { ProviderPackage } from "../provider-package"
|
|
||||||
import { AnthropicMessages } from "../protocols/anthropic-messages"
|
|
||||||
import { Auth } from "../route/auth"
|
|
||||||
import { Route, type RouteDefaultsInput } from "../route/client"
|
|
||||||
import { Endpoint } from "../route/endpoint"
|
|
||||||
import { Framing } from "../route/framing"
|
|
||||||
import { Protocol } from "../route/protocol"
|
|
||||||
import { ProviderID, type ModelID, type ProviderOptions } from "../schema"
|
|
||||||
import { GoogleVertexShared } from "./google-vertex-shared"
|
|
||||||
|
|
||||||
const VERSION = "vertex-2023-10-16" as const
|
|
||||||
|
|
||||||
// models.dev uses this provider id even though the API contract is Anthropic Messages.
|
|
||||||
export const id = ProviderID.make("google-vertex-anthropic")
|
|
||||||
|
|
||||||
export type Config = RouteDefaultsInput &
|
|
||||||
GoogleVertexShared.OAuthOptions & {
|
|
||||||
readonly baseURL?: string
|
|
||||||
readonly location?: string
|
|
||||||
readonly project?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Settings extends ProviderPackage.Settings {
|
|
||||||
readonly accessToken?: string
|
|
||||||
readonly apiKey?: never
|
|
||||||
readonly baseURL?: string
|
|
||||||
readonly location?: string
|
|
||||||
readonly project?: string
|
|
||||||
readonly providerOptions?: ProviderOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
const route = Route.make({
|
|
||||||
id: "google-vertex-messages",
|
|
||||||
provider: id,
|
|
||||||
providerMetadataKey: "anthropic",
|
|
||||||
protocol: Protocol.make({
|
|
||||||
id: AnthropicMessages.protocol.id,
|
|
||||||
body: {
|
|
||||||
schema: Schema.Struct({
|
|
||||||
...Struct.omit(AnthropicMessages.AnthropicMessagesBody.fields, ["model"]),
|
|
||||||
anthropic_version: Schema.Literal(VERSION),
|
|
||||||
}),
|
|
||||||
from: (request) =>
|
|
||||||
AnthropicMessages.protocol.body.from(request).pipe(
|
|
||||||
Effect.map((body) => ({
|
|
||||||
...Struct.omit(body, ["model"]),
|
|
||||||
anthropic_version: VERSION,
|
|
||||||
})),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
stream: AnthropicMessages.protocol.stream,
|
|
||||||
}),
|
|
||||||
endpoint: Endpoint.path(({ request }) => `/${request.model.id}:streamRawPredict`),
|
|
||||||
auth: Auth.none,
|
|
||||||
framing: Framing.sse,
|
|
||||||
})
|
|
||||||
|
|
||||||
export const routes = [route]
|
|
||||||
|
|
||||||
const configuredRoute = (input: Config) => {
|
|
||||||
if ("apiKey" in input && input.apiKey !== undefined)
|
|
||||||
throw new Error("Google Vertex Messages does not support API keys")
|
|
||||||
const {
|
|
||||||
accessToken: _accessToken,
|
|
||||||
auth: _auth,
|
|
||||||
baseURL,
|
|
||||||
location: inputLocation,
|
|
||||||
project: inputProject,
|
|
||||||
...rest
|
|
||||||
} = input
|
|
||||||
const location = GoogleVertexShared.location(inputLocation, "global")
|
|
||||||
const project = GoogleVertexShared.project(inputProject)
|
|
||||||
return route.with({
|
|
||||||
...rest,
|
|
||||||
endpoint: {
|
|
||||||
baseURL:
|
|
||||||
baseURL ??
|
|
||||||
`https://${GoogleVertexShared.host(location)}/v1/projects/${GoogleVertexShared.requireProject(project)}/locations/${location}/publishers/anthropic/models`,
|
|
||||||
},
|
|
||||||
auth: GoogleVertexShared.oauth(input, project),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const configure = (input: Config = {}) => {
|
|
||||||
const route = configuredRoute(input)
|
|
||||||
return {
|
|
||||||
id,
|
|
||||||
model: (modelID: string | ModelID) => route.model({ id: modelID }),
|
|
||||||
configure,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const provider = {
|
|
||||||
id,
|
|
||||||
configure,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const model: ProviderPackage.Definition<Settings>["model"] = (modelID, settings) => {
|
|
||||||
if (settings.apiKey !== undefined) throw new Error("Google Vertex Messages does not support API keys")
|
|
||||||
return configure({
|
|
||||||
accessToken: settings.accessToken,
|
|
||||||
baseURL: settings.baseURL,
|
|
||||||
headers: settings.headers === undefined ? undefined : { ...settings.headers },
|
|
||||||
http: settings.body === undefined ? undefined : { body: { ...settings.body } },
|
|
||||||
limits: settings.limits,
|
|
||||||
location: settings.location,
|
|
||||||
project: settings.project,
|
|
||||||
providerOptions: settings.providerOptions,
|
|
||||||
}).model(modelID)
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
import type { ProviderPackage } from "../provider-package"
|
import type { ProviderPackage } from "../provider-package"
|
||||||
import { Gemini } from "../protocols/gemini"
|
import { GoogleVertexGemini } from "../protocols/google-vertex-gemini"
|
||||||
import { Auth } from "../route/auth"
|
import { Auth } from "../route/auth"
|
||||||
import { Route, type RouteDefaultsInput } from "../route/client"
|
import type { RouteDefaultsInput } from "../route/client"
|
||||||
import { Endpoint } from "../route/endpoint"
|
|
||||||
import { Framing } from "../route/framing"
|
|
||||||
import { ProviderID, type ModelID, type ProviderOptions } from "../schema"
|
import { ProviderID, type ModelID, type ProviderOptions } from "../schema"
|
||||||
import { GoogleVertexShared } from "./google-vertex-shared"
|
import { GoogleVertexShared } from "./google-vertex-shared"
|
||||||
|
|
||||||
@@ -27,20 +25,7 @@ export type Settings = ProviderPackage.Settings &
|
|||||||
readonly providerOptions?: ProviderOptions
|
readonly providerOptions?: ProviderOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
const route = Route.make({
|
export const routes = [GoogleVertexGemini.route]
|
||||||
id: "google-vertex-gemini",
|
|
||||||
provider: id,
|
|
||||||
providerMetadataKey: "google",
|
|
||||||
protocol: Gemini.protocol,
|
|
||||||
endpoint: Endpoint.path(({ request }) => {
|
|
||||||
const model = String(request.model.id)
|
|
||||||
return `/${model.startsWith("endpoints/") ? model : `models/${model}`}:streamGenerateContent?alt=sse`
|
|
||||||
}),
|
|
||||||
auth: Auth.none,
|
|
||||||
framing: Framing.sse,
|
|
||||||
})
|
|
||||||
|
|
||||||
export const routes = [route]
|
|
||||||
|
|
||||||
const configuredRoute = (input: Config, modelID: string | ModelID) => {
|
const configuredRoute = (input: Config, modelID: string | ModelID) => {
|
||||||
const {
|
const {
|
||||||
@@ -63,7 +48,7 @@ const configuredRoute = (input: Config, modelID: string | ModelID) => {
|
|||||||
(apiKey
|
(apiKey
|
||||||
? "https://aiplatform.googleapis.com/v1/publishers/google"
|
? "https://aiplatform.googleapis.com/v1/publishers/google"
|
||||||
: `https://${GoogleVertexShared.host(location)}/v1beta1/projects/${GoogleVertexShared.requireProject(project)}/locations/${location}${endpointModel ? "" : "/publishers/google"}`)
|
: `https://${GoogleVertexShared.host(location)}/v1beta1/projects/${GoogleVertexShared.requireProject(project)}/locations/${location}${endpointModel ? "" : "/publishers/google"}`)
|
||||||
return route.with({
|
return GoogleVertexGemini.route.with({
|
||||||
...rest,
|
...rest,
|
||||||
endpoint: { baseURL: endpoint },
|
endpoint: { baseURL: endpoint },
|
||||||
auth: apiKey === undefined ? GoogleVertexShared.oauth(input, project) : Auth.header("x-goog-api-key", apiKey),
|
auth: apiKey === undefined ? GoogleVertexShared.oauth(input, project) : Auth.header("x-goog-api-key", apiKey),
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export { model } from "../google-vertex-anthropic"
|
||||||
|
export type { Settings } from "../google-vertex-anthropic"
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export { model } from "../google-vertex-chat"
|
|
||||||
export type { Settings } from "../google-vertex-chat"
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export { model } from "../google-vertex"
|
|
||||||
export type { Settings } from "../google-vertex"
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export { model } from "../google-vertex-messages"
|
|
||||||
export type { Settings } from "../google-vertex-messages"
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export { model } from "../google-vertex-responses"
|
|
||||||
export type { Settings } from "../google-vertex-responses"
|
|
||||||
@@ -7,9 +7,7 @@ export { CloudflareAIGateway, CloudflareWorkersAI } from "./cloudflare"
|
|||||||
export * as GitHubCopilot from "./github-copilot"
|
export * as GitHubCopilot from "./github-copilot"
|
||||||
export * as Google from "./google"
|
export * as Google from "./google"
|
||||||
export * as GoogleVertex from "./google-vertex"
|
export * as GoogleVertex from "./google-vertex"
|
||||||
export * as GoogleVertexChat from "./google-vertex-chat"
|
export * as GoogleVertexAnthropic from "./google-vertex-anthropic"
|
||||||
export * as GoogleVertexMessages from "./google-vertex-messages"
|
|
||||||
export * as GoogleVertexResponses from "./google-vertex-responses"
|
|
||||||
export * as OpenAI from "./openai"
|
export * as OpenAI from "./openai"
|
||||||
export * as OpenAICompatible from "./openai-compatible"
|
export * as OpenAICompatible from "./openai-compatible"
|
||||||
export * as OpenAICompatibleResponses from "./openai-compatible-responses"
|
export * as OpenAICompatibleResponses from "./openai-compatible-responses"
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ import * as Cloudflare from "../src/providers/cloudflare"
|
|||||||
import * as GitHubCopilot from "../src/providers/github-copilot"
|
import * as GitHubCopilot from "../src/providers/github-copilot"
|
||||||
import * as Google from "../src/providers/google"
|
import * as Google from "../src/providers/google"
|
||||||
import * as GoogleVertex from "../src/providers/google-vertex"
|
import * as GoogleVertex from "../src/providers/google-vertex"
|
||||||
import * as GoogleVertexChat from "../src/providers/google-vertex-chat"
|
import * as GoogleVertexAnthropic from "../src/providers/google-vertex-anthropic"
|
||||||
import * as GoogleVertexMessages from "../src/providers/google-vertex-messages"
|
|
||||||
import * as GoogleVertexResponses from "../src/providers/google-vertex-responses"
|
|
||||||
import * as OpenAI from "../src/providers/openai"
|
import * as OpenAI from "../src/providers/openai"
|
||||||
import * as OpenAICompatible from "../src/providers/openai-compatible"
|
import * as OpenAICompatible from "../src/providers/openai-compatible"
|
||||||
import * as OpenRouter from "../src/providers/openrouter"
|
import * as OpenRouter from "../src/providers/openrouter"
|
||||||
@@ -173,56 +171,20 @@ GoogleVertex.configure({ accessToken: "vertex-token", apiKey: "vertex-key", proj
|
|||||||
// @ts-expect-error Vertex Gemini package settings accept only one auth source.
|
// @ts-expect-error Vertex Gemini package settings accept only one auth source.
|
||||||
GoogleVertex.model("gemini-3.5-flash", { accessToken: "vertex-token", apiKey: "vertex-key", project: "project" })
|
GoogleVertex.model("gemini-3.5-flash", { accessToken: "vertex-token", apiKey: "vertex-key", project: "project" })
|
||||||
|
|
||||||
GoogleVertexChat.configure({ accessToken: "vertex-token", project: "project" }).model("deepseek-ai/deepseek-v3.2-maas")
|
GoogleVertexAnthropic.configure({ accessToken: "vertex-token", project: "project" }).model("claude-sonnet-4-6")
|
||||||
GoogleVertexChat.configure({ auth: RuntimeAuth.bearer("vertex-token"), project: "project" }).model(
|
// @ts-expect-error Vertex Anthropic package settings do not accept API keys.
|
||||||
"deepseek-ai/deepseek-v3.2-maas",
|
GoogleVertexAnthropic.model("claude-sonnet-4-6", { apiKey: "vertex-key", project: "project" })
|
||||||
)
|
GoogleVertexAnthropic.configure({ auth: RuntimeAuth.bearer("vertex-token"), project: "project" }).model(
|
||||||
// @ts-expect-error Vertex Chat package settings do not accept API keys.
|
|
||||||
GoogleVertexChat.model("deepseek-ai/deepseek-v3.2-maas", { apiKey: "vertex-key", project: "project" })
|
|
||||||
GoogleVertexChat.configure({ accessToken: "vertex-token", project: "project" }).model(
|
|
||||||
"deepseek-ai/deepseek-v3.2-maas",
|
|
||||||
// @ts-expect-error Vertex Chat model selectors only accept model ids.
|
|
||||||
{},
|
|
||||||
)
|
|
||||||
GoogleVertexChat.configure({
|
|
||||||
accessToken: "vertex-token",
|
|
||||||
// @ts-expect-error Vertex Chat config accepts only one auth source.
|
|
||||||
auth: RuntimeAuth.bearer("vertex-token"),
|
|
||||||
project: "project",
|
|
||||||
})
|
|
||||||
|
|
||||||
GoogleVertexResponses.configure({ accessToken: "vertex-token", project: "project" }).model("xai/grok-4.20-reasoning")
|
|
||||||
GoogleVertexResponses.configure({ auth: RuntimeAuth.bearer("vertex-token"), project: "project" }).model(
|
|
||||||
"xai/grok-4.20-reasoning",
|
|
||||||
)
|
|
||||||
// @ts-expect-error Vertex Responses package settings do not accept API keys.
|
|
||||||
GoogleVertexResponses.model("xai/grok-4.20-reasoning", { apiKey: "vertex-key", project: "project" })
|
|
||||||
GoogleVertexResponses.configure({ accessToken: "vertex-token", project: "project" }).model(
|
|
||||||
"xai/grok-4.20-reasoning",
|
|
||||||
// @ts-expect-error Vertex Responses model selectors only accept model ids.
|
|
||||||
{},
|
|
||||||
)
|
|
||||||
GoogleVertexResponses.configure({
|
|
||||||
accessToken: "vertex-token",
|
|
||||||
// @ts-expect-error Vertex Responses config accepts only one auth source.
|
|
||||||
auth: RuntimeAuth.bearer("vertex-token"),
|
|
||||||
project: "project",
|
|
||||||
})
|
|
||||||
|
|
||||||
GoogleVertexMessages.configure({ accessToken: "vertex-token", project: "project" }).model("claude-sonnet-4-6")
|
|
||||||
// @ts-expect-error Vertex Messages package settings do not accept API keys.
|
|
||||||
GoogleVertexMessages.model("claude-sonnet-4-6", { apiKey: "vertex-key", project: "project" })
|
|
||||||
GoogleVertexMessages.configure({ auth: RuntimeAuth.bearer("vertex-token"), project: "project" }).model(
|
|
||||||
"claude-sonnet-4-6",
|
"claude-sonnet-4-6",
|
||||||
)
|
)
|
||||||
GoogleVertexMessages.configure({ accessToken: "vertex-token", project: "project" }).model(
|
GoogleVertexAnthropic.configure({ accessToken: "vertex-token", project: "project" }).model(
|
||||||
"claude-sonnet-4-6",
|
"claude-sonnet-4-6",
|
||||||
// @ts-expect-error Vertex Messages model selectors only accept model ids.
|
// @ts-expect-error Vertex Anthropic model selectors only accept model ids.
|
||||||
{},
|
{},
|
||||||
)
|
)
|
||||||
GoogleVertexMessages.configure({
|
GoogleVertexAnthropic.configure({
|
||||||
accessToken: "vertex-token",
|
accessToken: "vertex-token",
|
||||||
// @ts-expect-error Vertex Messages config accepts only one auth source.
|
// @ts-expect-error Vertex Anthropic config accepts only one auth source.
|
||||||
auth: RuntimeAuth.bearer("vertex-token"),
|
auth: RuntimeAuth.bearer("vertex-token"),
|
||||||
project: "project",
|
project: "project",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -17,16 +17,12 @@ describe("provider package entrypoints", () => {
|
|||||||
import("@opencode-ai/ai/providers/azure/chat"),
|
import("@opencode-ai/ai/providers/azure/chat"),
|
||||||
import("@opencode-ai/ai/providers/google"),
|
import("@opencode-ai/ai/providers/google"),
|
||||||
import("@opencode-ai/ai/providers/google-vertex"),
|
import("@opencode-ai/ai/providers/google-vertex"),
|
||||||
import("@opencode-ai/ai/providers/google-vertex/gemini"),
|
import("@opencode-ai/ai/providers/google-vertex/anthropic"),
|
||||||
import("@opencode-ai/ai/providers/google-vertex/chat"),
|
|
||||||
import("@opencode-ai/ai/providers/google-vertex/responses"),
|
|
||||||
import("@opencode-ai/ai/providers/google-vertex/messages"),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
for (const module of modules) expect(module.model).toBeFunction()
|
for (const module of modules) expect(module.model).toBeFunction()
|
||||||
expect(modules[0].model).toBe(modules[1].model)
|
expect(modules[0].model).toBe(modules[1].model)
|
||||||
expect(modules[8].model).toBe(modules[9].model)
|
expect(modules[8].model).toBe(modules[9].model)
|
||||||
expect(modules[12].model).toBe(modules[13].model)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test("maps package settings onto the executable model", () => {
|
test("maps package settings onto the executable model", () => {
|
||||||
@@ -183,35 +179,20 @@ describe("provider package entrypoints", () => {
|
|||||||
|
|
||||||
test("selects Vertex entrypoints with the same model contract", async () => {
|
test("selects Vertex entrypoints with the same model contract", async () => {
|
||||||
const GoogleVertex = await import("@opencode-ai/ai/providers/google-vertex")
|
const GoogleVertex = await import("@opencode-ai/ai/providers/google-vertex")
|
||||||
const GoogleVertexGemini = await import("@opencode-ai/ai/providers/google-vertex/gemini")
|
const GoogleVertexAnthropic = await import("@opencode-ai/ai/providers/google-vertex/anthropic")
|
||||||
const GoogleVertexChat = await import("@opencode-ai/ai/providers/google-vertex/chat")
|
|
||||||
const GoogleVertexResponses = await import("@opencode-ai/ai/providers/google-vertex/responses")
|
|
||||||
const GoogleVertexMessages = await import("@opencode-ai/ai/providers/google-vertex/messages")
|
|
||||||
const gemini = GoogleVertex.model("gemini-3.5-flash", {
|
const gemini = GoogleVertex.model("gemini-3.5-flash", {
|
||||||
apiKey: "fixture",
|
apiKey: "fixture",
|
||||||
headers: { "x-application": "opencode" },
|
headers: { "x-application": "opencode" },
|
||||||
body: { safetySettings: [] },
|
body: { safetySettings: [] },
|
||||||
limits: { context: 1_000_000, output: 65_536 },
|
limits: { context: 1_000_000, output: 65_536 },
|
||||||
})
|
})
|
||||||
const messages = GoogleVertexMessages.model("claude-sonnet-4-6", {
|
const anthropic = GoogleVertexAnthropic.model("claude-sonnet-4-6", {
|
||||||
accessToken: "fixture",
|
|
||||||
location: "global",
|
|
||||||
project: "vertex-project",
|
|
||||||
})
|
|
||||||
const chat = GoogleVertexChat.model("deepseek-ai/deepseek-v3.2-maas", {
|
|
||||||
accessToken: "fixture",
|
|
||||||
location: "global",
|
|
||||||
project: "vertex-project",
|
|
||||||
})
|
|
||||||
const responses = GoogleVertexResponses.model("xai/grok-4.20-reasoning", {
|
|
||||||
accessToken: "fixture",
|
accessToken: "fixture",
|
||||||
location: "global",
|
location: "global",
|
||||||
project: "vertex-project",
|
project: "vertex-project",
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(GoogleVertexGemini.model).toBe(GoogleVertex.model)
|
|
||||||
expect(gemini.route.id).toBe("google-vertex-gemini")
|
expect(gemini.route.id).toBe("google-vertex-gemini")
|
||||||
expect(gemini.route.protocol).toBe("gemini")
|
|
||||||
expect(gemini.route.endpoint.baseURL).toBe("https://aiplatform.googleapis.com/v1/publishers/google")
|
expect(gemini.route.endpoint.baseURL).toBe("https://aiplatform.googleapis.com/v1/publishers/google")
|
||||||
expect(gemini.route.defaults.headers).toEqual({ "x-application": "opencode" })
|
expect(gemini.route.defaults.headers).toEqual({ "x-application": "opencode" })
|
||||||
expect(gemini.route.defaults.http?.body).toEqual({ safetySettings: [] })
|
expect(gemini.route.defaults.http?.body).toEqual({ safetySettings: [] })
|
||||||
@@ -223,31 +204,15 @@ describe("provider package entrypoints", () => {
|
|||||||
project: "vertex-project",
|
project: "vertex-project",
|
||||||
}).route.endpoint.baseURL,
|
}).route.endpoint.baseURL,
|
||||||
).toBe("https://aiplatform.eu.rep.googleapis.com/v1beta1/projects/vertex-project/locations/eu/publishers/google")
|
).toBe("https://aiplatform.eu.rep.googleapis.com/v1beta1/projects/vertex-project/locations/eu/publishers/google")
|
||||||
expect(messages.route.id).toBe("google-vertex-messages")
|
expect(anthropic.route.id).toBe("google-vertex-anthropic")
|
||||||
expect(messages.route.protocol).toBe("anthropic-messages")
|
expect(anthropic.route.endpoint.baseURL).toBe(
|
||||||
expect(messages.route.endpoint.baseURL).toBe(
|
|
||||||
"https://aiplatform.googleapis.com/v1/projects/vertex-project/locations/global/publishers/anthropic/models",
|
"https://aiplatform.googleapis.com/v1/projects/vertex-project/locations/global/publishers/anthropic/models",
|
||||||
)
|
)
|
||||||
expect(chat.route.id).toBe("google-vertex-chat")
|
|
||||||
expect(chat.route.protocol).toBe("openai-chat")
|
|
||||||
expect(chat.route.endpoint).toMatchObject({
|
|
||||||
baseURL: "https://aiplatform.googleapis.com/v1/projects/vertex-project/locations/global/endpoints/openapi",
|
|
||||||
path: "/chat/completions",
|
|
||||||
})
|
|
||||||
expect(responses.route.id).toBe("google-vertex-responses")
|
|
||||||
expect(responses.route.protocol).toBe("openai-responses")
|
|
||||||
expect(responses.route.endpoint).toMatchObject({
|
|
||||||
baseURL: "https://aiplatform.googleapis.com/v1/projects/vertex-project/locations/global/endpoints/openapi",
|
|
||||||
path: "/responses",
|
|
||||||
})
|
|
||||||
expect(responses.route.defaults.providerOptions).toEqual({ openai: { store: false } })
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test("rejects conflicting Vertex auth settings at runtime", async () => {
|
test("rejects conflicting Vertex auth settings at runtime", async () => {
|
||||||
const GoogleVertex = await import("@opencode-ai/ai/providers/google-vertex")
|
const GoogleVertex = await import("@opencode-ai/ai/providers/google-vertex")
|
||||||
const GoogleVertexChat = await import("@opencode-ai/ai/providers/google-vertex/chat")
|
const GoogleVertexAnthropic = await import("@opencode-ai/ai/providers/google-vertex/anthropic")
|
||||||
const GoogleVertexMessages = await import("@opencode-ai/ai/providers/google-vertex/messages")
|
|
||||||
const GoogleVertexResponses = await import("@opencode-ai/ai/providers/google-vertex/responses")
|
|
||||||
const Providers = await import("@opencode-ai/ai/providers")
|
const Providers = await import("@opencode-ai/ai/providers")
|
||||||
expect(() =>
|
expect(() =>
|
||||||
Reflect.apply(GoogleVertex.model, undefined, [
|
Reflect.apply(GoogleVertex.model, undefined, [
|
||||||
@@ -260,37 +225,15 @@ describe("provider package entrypoints", () => {
|
|||||||
])
|
])
|
||||||
expect(() => configured.model("gemini-3.5-flash")).toThrow("Google Vertex accessToken cannot be combined with auth")
|
expect(() => configured.model("gemini-3.5-flash")).toThrow("Google Vertex accessToken cannot be combined with auth")
|
||||||
expect(() =>
|
expect(() =>
|
||||||
Reflect.apply(GoogleVertexMessages.model, undefined, [
|
Reflect.apply(GoogleVertexAnthropic.model, undefined, [
|
||||||
"claude-sonnet-4-6",
|
"claude-sonnet-4-6",
|
||||||
{ apiKey: "fixture", project: "vertex-project" },
|
{ apiKey: "fixture", project: "vertex-project" },
|
||||||
]),
|
]),
|
||||||
).toThrow("Google Vertex Messages does not support API keys")
|
).toThrow("Google Vertex Anthropic does not support API keys")
|
||||||
expect(() =>
|
expect(() =>
|
||||||
Reflect.apply(Providers.GoogleVertexMessages.configure, undefined, [
|
Reflect.apply(Providers.GoogleVertexAnthropic.configure, undefined, [
|
||||||
{ apiKey: "fixture", project: "vertex-project" },
|
{ apiKey: "fixture", project: "vertex-project" },
|
||||||
]),
|
]),
|
||||||
).toThrow("Google Vertex Messages does not support API keys")
|
).toThrow("Google Vertex Anthropic does not support API keys")
|
||||||
expect(() =>
|
|
||||||
Reflect.apply(GoogleVertexChat.model, undefined, [
|
|
||||||
"deepseek-ai/deepseek-v3.2-maas",
|
|
||||||
{ apiKey: "fixture", project: "vertex-project" },
|
|
||||||
]),
|
|
||||||
).toThrow("Google Vertex Chat does not support API keys")
|
|
||||||
expect(() =>
|
|
||||||
Reflect.apply(Providers.GoogleVertexChat.configure, undefined, [
|
|
||||||
{ apiKey: "fixture", project: "vertex-project" },
|
|
||||||
]),
|
|
||||||
).toThrow("Google Vertex Chat does not support API keys")
|
|
||||||
expect(() =>
|
|
||||||
Reflect.apply(GoogleVertexResponses.model, undefined, [
|
|
||||||
"xai/grok-4.20-reasoning",
|
|
||||||
{ apiKey: "fixture", project: "vertex-project" },
|
|
||||||
]),
|
|
||||||
).toThrow("Google Vertex Responses does not support API keys")
|
|
||||||
expect(() =>
|
|
||||||
Reflect.apply(Providers.GoogleVertexResponses.configure, undefined, [
|
|
||||||
{ apiKey: "fixture", project: "vertex-project" },
|
|
||||||
]),
|
|
||||||
).toThrow("Google Vertex Responses does not support API keys")
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ import { describe, expect } from "bun:test"
|
|||||||
import { Effect } from "effect"
|
import { Effect } from "effect"
|
||||||
import { HttpClientRequest } from "effect/unstable/http"
|
import { HttpClientRequest } from "effect/unstable/http"
|
||||||
import { LLM } from "../../src"
|
import { LLM } from "../../src"
|
||||||
import { GoogleVertex, GoogleVertexChat, GoogleVertexMessages, GoogleVertexResponses } from "../../src/providers"
|
import { GoogleVertex, GoogleVertexAnthropic } from "../../src/providers"
|
||||||
import { LLMClient } from "../../src/route"
|
import { LLMClient } from "../../src/route"
|
||||||
import { it } from "../lib/effect"
|
import { it } from "../lib/effect"
|
||||||
import { dynamicResponse } from "../lib/http"
|
import { dynamicResponse } from "../lib/http"
|
||||||
import { deltaChunk, finishChunk } from "../lib/openai-chunks"
|
|
||||||
import { sseEvents } from "../lib/sse"
|
import { sseEvents } from "../lib/sse"
|
||||||
|
|
||||||
describe("Google Vertex providers", () => {
|
describe("Google Vertex providers", () => {
|
||||||
@@ -57,7 +56,7 @@ describe("Google Vertex providers", () => {
|
|||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const response = yield* LLMClient.generate(
|
const response = yield* LLMClient.generate(
|
||||||
LLM.request({
|
LLM.request({
|
||||||
model: GoogleVertexMessages.configure({
|
model: GoogleVertexAnthropic.configure({
|
||||||
accessToken: "vertex-token",
|
accessToken: "vertex-token",
|
||||||
location: "eu",
|
location: "eu",
|
||||||
project: "vertex-project",
|
project: "vertex-project",
|
||||||
@@ -100,91 +99,11 @@ describe("Google Vertex providers", () => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.effect("sends MaaS requests through Vertex Chat Completions", () =>
|
it.effect("protects the Vertex Anthropic API version from body overlays", () =>
|
||||||
Effect.gen(function* () {
|
|
||||||
const response = yield* LLMClient.generate(
|
|
||||||
LLM.request({
|
|
||||||
model: GoogleVertexChat.configure({
|
|
||||||
accessToken: "vertex-token",
|
|
||||||
location: "global",
|
|
||||||
project: "vertex-project",
|
|
||||||
}).model("deepseek-ai/deepseek-v3.2-maas"),
|
|
||||||
prompt: "Say hello.",
|
|
||||||
}),
|
|
||||||
).pipe(
|
|
||||||
Effect.provide(
|
|
||||||
dynamicResponse((input) =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
const request = yield* HttpClientRequest.toWeb(input.request).pipe(Effect.orDie)
|
|
||||||
expect(request.url).toBe(
|
|
||||||
"https://aiplatform.googleapis.com/v1/projects/vertex-project/locations/global/endpoints/openapi/chat/completions",
|
|
||||||
)
|
|
||||||
expect(request.headers.get("authorization")).toBe("Bearer vertex-token")
|
|
||||||
expect(yield* Effect.promise(() => request.json())).toMatchObject({
|
|
||||||
model: "deepseek-ai/deepseek-v3.2-maas",
|
|
||||||
messages: [{ role: "user", content: "Say hello." }],
|
|
||||||
stream: true,
|
|
||||||
stream_options: { include_usage: true },
|
|
||||||
})
|
|
||||||
return input.respond(sseEvents(deltaChunk({ content: "Hello." }), finishChunk("stop")), {
|
|
||||||
headers: { "content-type": "text/event-stream" },
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(response.text).toBe("Hello.")
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
it.effect("sends Grok requests through Vertex Responses", () =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
const response = yield* LLMClient.generate(
|
|
||||||
LLM.request({
|
|
||||||
model: GoogleVertexResponses.configure({
|
|
||||||
accessToken: "vertex-token",
|
|
||||||
location: "global",
|
|
||||||
project: "vertex-project",
|
|
||||||
}).model("xai/grok-4.20-reasoning"),
|
|
||||||
prompt: "Say hello.",
|
|
||||||
}),
|
|
||||||
).pipe(
|
|
||||||
Effect.provide(
|
|
||||||
dynamicResponse((input) =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
const request = yield* HttpClientRequest.toWeb(input.request).pipe(Effect.orDie)
|
|
||||||
expect(request.url).toBe(
|
|
||||||
"https://aiplatform.googleapis.com/v1/projects/vertex-project/locations/global/endpoints/openapi/responses",
|
|
||||||
)
|
|
||||||
expect(request.headers.get("authorization")).toBe("Bearer vertex-token")
|
|
||||||
expect(yield* Effect.promise(() => request.json())).toMatchObject({
|
|
||||||
model: "xai/grok-4.20-reasoning",
|
|
||||||
input: [{ role: "user", content: [{ type: "input_text", text: "Say hello." }] }],
|
|
||||||
store: false,
|
|
||||||
stream: true,
|
|
||||||
})
|
|
||||||
return input.respond(
|
|
||||||
sseEvents(
|
|
||||||
{ type: "response.output_text.delta", item_id: "msg_1", delta: "Hello." },
|
|
||||||
{ type: "response.completed", response: { id: "resp_1" } },
|
|
||||||
),
|
|
||||||
{ headers: { "content-type": "text/event-stream" } },
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(response.text).toBe("Hello.")
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
it.effect("protects the Vertex Messages API version from body overlays", () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const error = yield* LLMClient.prepare(
|
const error = yield* LLMClient.prepare(
|
||||||
LLM.request({
|
LLM.request({
|
||||||
model: GoogleVertexMessages.configure({
|
model: GoogleVertexAnthropic.configure({
|
||||||
accessToken: "vertex-token",
|
accessToken: "vertex-token",
|
||||||
http: { body: { anthropic_version: "wrong" } },
|
http: { body: { anthropic_version: "wrong" } },
|
||||||
project: "vertex-project",
|
project: "vertex-project",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { describe, expect } from "bun:test"
|
import { describe, expect } from "bun:test"
|
||||||
import { ConfigProvider, Effect, Layer, Stream } from "effect"
|
import { ConfigProvider, Effect, Layer, Stream } from "effect"
|
||||||
import { Headers, HttpClientRequest } from "effect/unstable/http"
|
import { Headers, HttpClientRequest } from "effect/unstable/http"
|
||||||
import { LLM, LLMError, Message, Model, ToolCallPart, Usage } from "../../src"
|
import { LLM, LLMError, LLMEvent, Message, Model, ToolCallPart, Usage } from "../../src"
|
||||||
import { Auth, LLMClient, RequestExecutor, WebSocketExecutor } from "../../src/route"
|
import { Auth, LLMClient, RequestExecutor, WebSocketExecutor } from "../../src/route"
|
||||||
import * as Azure from "../../src/providers/azure"
|
import * as Azure from "../../src/providers/azure"
|
||||||
import * as OpenAI from "../../src/providers/openai"
|
import * as OpenAI from "../../src/providers/openai"
|
||||||
@@ -1259,6 +1259,62 @@ describe("OpenAI Responses route", () => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it.effect("finalizes an empty function call when the terminal response omits output_item.done", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const body = sseEvents(
|
||||||
|
{
|
||||||
|
type: "response.output_item.added",
|
||||||
|
item: { type: "function_call", id: "item_1", call_id: "call_1", name: "patch", arguments: "" },
|
||||||
|
},
|
||||||
|
{ type: "response.completed", response: { usage: { input_tokens: 5, output_tokens: 1 } } },
|
||||||
|
)
|
||||||
|
const response = yield* LLMClient.generate(
|
||||||
|
LLM.updateRequest(request, {
|
||||||
|
tools: [{ name: "patch", description: "Apply a patch", inputSchema: { type: "object" } }],
|
||||||
|
}),
|
||||||
|
).pipe(Effect.provide(fixedResponse(body)))
|
||||||
|
|
||||||
|
expect(response.events).toContainEqual({
|
||||||
|
type: "tool-call",
|
||||||
|
id: "call_1",
|
||||||
|
name: "patch",
|
||||||
|
input: {},
|
||||||
|
providerExecuted: undefined,
|
||||||
|
providerMetadata: { openai: { itemId: "item_1" } },
|
||||||
|
})
|
||||||
|
expect(response.finishReason).toBe("tool-calls")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it.effect("rejects an incomplete pending function call", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const body = sseEvents(
|
||||||
|
{
|
||||||
|
type: "response.output_item.added",
|
||||||
|
item: { type: "function_call", id: "item_1", call_id: "call_1", name: "patch", arguments: "" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "response.incomplete",
|
||||||
|
response: { incomplete_details: { reason: "max_output_tokens" } },
|
||||||
|
},
|
||||||
|
)
|
||||||
|
const events: LLMEvent[] = []
|
||||||
|
const error = yield* LLMClient.stream(
|
||||||
|
LLM.updateRequest(request, {
|
||||||
|
tools: [{ name: "patch", description: "Apply a patch", inputSchema: { type: "object" } }],
|
||||||
|
}),
|
||||||
|
).pipe(
|
||||||
|
Stream.runForEach((event) => Effect.sync(() => events.push(event))),
|
||||||
|
Effect.flip,
|
||||||
|
Effect.provide(fixedResponse(body)),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(events.filter(LLMEvent.is.toolCall)).toEqual([])
|
||||||
|
expect(error.reason).toMatchObject({ _tag: "InvalidProviderOutput" })
|
||||||
|
expect(error.message).toContain("OpenAI Responses response incomplete with pending tool calls")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
it.effect("decodes web_search_call as provider-executed tool-call + tool-result", () =>
|
it.effect("decodes web_search_call as provider-executed tool-call + tool-result", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const item = {
|
const item = {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/app",
|
"name": "@opencode-ai/app",
|
||||||
"version": "1.18.3",
|
"version": "1.17.20",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
|
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||||
import { getFilename } from "@opencode-ai/core/util/path"
|
import { getFilename } from "@opencode-ai/core/util/path"
|
||||||
import type { GlobalSession, Project } from "@opencode-ai/sdk/v2/client"
|
|
||||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||||
|
import { useNavigate } from "@solidjs/router"
|
||||||
import { createMemo, onCleanup } from "solid-js"
|
import { createMemo, onCleanup } from "solid-js"
|
||||||
import { commandPaletteOptions, useCommand, type CommandOption } from "@/context/command"
|
import { useCommand, type CommandOption } from "@/context/command"
|
||||||
import { useFile } from "@/context/file"
|
import { useFile } from "@/context/file"
|
||||||
import { useGlobal } from "@/context/global"
|
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { useLayout, type LocalProject } from "@/context/layout"
|
import { useLayout } from "@/context/layout"
|
||||||
import { ServerConnection } from "@/context/server"
|
import { useServerSDK, type ServerSDK } from "@/context/server-sdk"
|
||||||
import { useServerSDK } from "@/context/server-sdk"
|
import { useServerSync } from "@/context/server-sync"
|
||||||
import { useTabs } from "@/context/tabs"
|
|
||||||
import { displayName, projectForSession } from "@/pages/layout/helpers"
|
|
||||||
import { createSessionTabs } from "@/pages/session/helpers"
|
import { createSessionTabs } from "@/pages/session/helpers"
|
||||||
import { useSessionLayout } from "@/pages/session/session-layout"
|
import { useSessionLayout } from "@/pages/session/session-layout"
|
||||||
|
import { decode64 } from "@/utils/base64"
|
||||||
|
|
||||||
export type CommandPaletteEntry = {
|
export type CommandPaletteEntry = {
|
||||||
id: string
|
id: string
|
||||||
@@ -25,8 +24,6 @@ export type CommandPaletteEntry = {
|
|||||||
path?: string
|
path?: string
|
||||||
directory?: string
|
directory?: string
|
||||||
sessionID?: string
|
sessionID?: string
|
||||||
server?: ServerConnection.Key
|
|
||||||
project?: LocalProject
|
|
||||||
archived?: number
|
archived?: number
|
||||||
updated?: number
|
updated?: number
|
||||||
}
|
}
|
||||||
@@ -78,25 +75,28 @@ export function createCommandPaletteFileOpener(onOpenFile?: (path: string) => vo
|
|||||||
|
|
||||||
export function createCommandPaletteModel(props: { filesOnly?: () => boolean; onOpenFile?: (path: string) => void }) {
|
export function createCommandPaletteModel(props: { filesOnly?: () => boolean; onOpenFile?: (path: string) => void }) {
|
||||||
const command = useCommand()
|
const command = useCommand()
|
||||||
const global = useGlobal()
|
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
|
const layout = useLayout()
|
||||||
const file = useFile()
|
const file = useFile()
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
|
const navigate = useNavigate()
|
||||||
const serverSDK = useServerSDK()()
|
const serverSDK = useServerSDK()()
|
||||||
const serverCtx = global.ensureServerCtx(serverSDK.server)
|
const serverSync = useServerSync()
|
||||||
const appTabs = useTabs()
|
const { params, tabs } = useSessionLayout()
|
||||||
const { tabs: sessionTabs } = useSessionLayout()
|
|
||||||
const openFile = createCommandPaletteFileOpener(props.onOpenFile)
|
const openFile = createCommandPaletteFileOpener(props.onOpenFile)
|
||||||
const state = { cleanup: undefined as (() => void) | void, committed: false }
|
const state = { cleanup: undefined as (() => void) | void, committed: false }
|
||||||
const filesOnly = () => props.filesOnly?.() ?? false
|
const filesOnly = () => props.filesOnly?.() ?? false
|
||||||
|
|
||||||
const allowedCommands = createMemo(() => {
|
const allowedCommands = createMemo(() => {
|
||||||
if (filesOnly()) return []
|
if (filesOnly()) return []
|
||||||
return commandPaletteOptions(command.options)
|
return command.options.filter(
|
||||||
|
(option) =>
|
||||||
|
!option.disabled && !option.hidden && !option.id.startsWith("suggested.") && option.id !== "file.open",
|
||||||
|
)
|
||||||
})
|
})
|
||||||
const commandEntries = createMemo(() => {
|
const commandEntries = createMemo(() => {
|
||||||
const category = language.t("palette.group.commands")
|
const category = language.t("palette.group.commands")
|
||||||
return allowedCommands().map((option) => createCommandPaletteCommandEntry(option, category))
|
return allowedCommands().map((option) => createCommandEntry(option, category))
|
||||||
})
|
})
|
||||||
const preferredCommandEntries = createMemo(() => {
|
const preferredCommandEntries = createMemo(() => {
|
||||||
const all = allowedCommands()
|
const all = allowedCommands()
|
||||||
@@ -105,11 +105,11 @@ export function createCommandPaletteModel(props: { filesOnly?: () => boolean; on
|
|||||||
const base = picked.length ? picked : all.slice(0, ENTRY_LIMIT)
|
const base = picked.length ? picked : all.slice(0, ENTRY_LIMIT)
|
||||||
const sorted = picked.length ? [...base].sort((a, b) => (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)) : base
|
const sorted = picked.length ? [...base].sort((a, b) => (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)) : base
|
||||||
const category = language.t("palette.group.commands")
|
const category = language.t("palette.group.commands")
|
||||||
return sorted.map((option) => createCommandPaletteCommandEntry(option, category))
|
return sorted.map((option) => createCommandEntry(option, category))
|
||||||
})
|
})
|
||||||
|
|
||||||
const tabState = createSessionTabs({
|
const tabState = createSessionTabs({
|
||||||
tabs: sessionTabs,
|
tabs,
|
||||||
pathFromTab: file.pathFromTab,
|
pathFromTab: file.pathFromTab,
|
||||||
normalizeTab: (tab) => (tab.startsWith("file://") ? file.tab(tab) : tab),
|
normalizeTab: (tab) => (tab.startsWith("file://") ? file.tab(tab) : tab),
|
||||||
})
|
})
|
||||||
@@ -140,12 +140,36 @@ export function createCommandPaletteModel(props: { filesOnly?: () => boolean; on
|
|||||||
.map((path) => createCommandPaletteFileEntry(path, category))
|
.map((path) => createCommandPaletteFileEntry(path, category))
|
||||||
})
|
})
|
||||||
|
|
||||||
const sessions = createServerSessionEntries({
|
const projectDirectory = createMemo(() => decode64(params.dir) ?? "")
|
||||||
server: ServerConnection.key(serverSDK.server),
|
const project = createMemo(() => {
|
||||||
opened: serverCtx.projects.list,
|
const directory = projectDirectory()
|
||||||
stored: () => serverCtx.sync.data.project,
|
if (!directory) return undefined
|
||||||
load: (search, signal) =>
|
return layout.projects.list().find((item) => item.worktree === directory || item.sandboxes?.includes(directory))
|
||||||
serverSDK.client.experimental.session.list({ roots: true, search, limit: 50 }, { signal }),
|
})
|
||||||
|
const workspaces = createMemo(() => {
|
||||||
|
const directory = projectDirectory()
|
||||||
|
const current = project()
|
||||||
|
if (!current) return directory ? [directory] : []
|
||||||
|
const dirs = [current.worktree, ...(current.sandboxes ?? [])]
|
||||||
|
if (directory && !dirs.includes(directory)) return [...dirs, directory]
|
||||||
|
return dirs
|
||||||
|
})
|
||||||
|
const homedir = createMemo(() => serverSync().data.path.home)
|
||||||
|
const sessions = createSessionEntries({
|
||||||
|
workspaces,
|
||||||
|
label: (directory) => {
|
||||||
|
const current = project()
|
||||||
|
const kind =
|
||||||
|
current && directory === current.worktree
|
||||||
|
? language.t("workspace.type.local")
|
||||||
|
: language.t("workspace.type.sandbox")
|
||||||
|
const [store] = serverSync().child(directory, { bootstrap: false })
|
||||||
|
const home = homedir()
|
||||||
|
const path = home ? directory.replace(home, "~") : directory
|
||||||
|
const name = store.vcs?.branch ?? getFilename(directory)
|
||||||
|
return `${kind} : ${name || path}`
|
||||||
|
},
|
||||||
|
load: (directory) => serverSDK.client.session.list({ directory, roots: true }),
|
||||||
untitled: () => language.t("command.session.new"),
|
untitled: () => language.t("command.session.new"),
|
||||||
category: () => language.t("command.category.session"),
|
category: () => language.t("command.category.session"),
|
||||||
})
|
})
|
||||||
@@ -167,17 +191,8 @@ export function createCommandPaletteModel(props: { filesOnly?: () => boolean; on
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (item.type === "session") {
|
if (item.type === "session") {
|
||||||
if (!item.sessionID || !item.server) return
|
if (!item.directory || !item.sessionID) return
|
||||||
const directory = item.project?.worktree ?? item.directory
|
navigate(`/${base64Encode(item.directory)}/session/${item.sessionID}`)
|
||||||
if (directory) {
|
|
||||||
serverCtx.projects.open(directory)
|
|
||||||
serverCtx.projects.touch(directory)
|
|
||||||
}
|
|
||||||
const tab = appTabs.addSessionTab({
|
|
||||||
server: item.server,
|
|
||||||
sessionId: item.sessionID,
|
|
||||||
})
|
|
||||||
appTabs.select(tab)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!item.path) return
|
if (!item.path) return
|
||||||
@@ -203,7 +218,7 @@ export function createCommandPaletteModel(props: { filesOnly?: () => boolean; on
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createCommandPaletteCommandEntry(option: CommandOption, category: string): CommandPaletteEntry {
|
function createCommandEntry(option: CommandOption, category: string): CommandPaletteEntry {
|
||||||
return {
|
return {
|
||||||
id: "command:" + option.id,
|
id: "command:" + option.id,
|
||||||
type: "command",
|
type: "command",
|
||||||
@@ -215,65 +230,96 @@ export function createCommandPaletteCommandEntry(option: CommandOption, category
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createServerSessionEntries(props: {
|
function createSessionEntries(props: {
|
||||||
server: ServerConnection.Key
|
workspaces: () => string[]
|
||||||
opened: () => LocalProject[]
|
label: (directory: string) => string
|
||||||
stored: () => Project[]
|
load: (directory: string) => ReturnType<ServerSDK["client"]["session"]["list"]>
|
||||||
load: (search: string, signal: AbortSignal) => Promise<{ data?: GlobalSession[] }>
|
|
||||||
untitled: () => string
|
untitled: () => string
|
||||||
category: () => string
|
category: () => string
|
||||||
}) {
|
}) {
|
||||||
let abort: AbortController | undefined
|
const state: {
|
||||||
|
token: number
|
||||||
|
inflight: Promise<CommandPaletteEntry[]> | undefined
|
||||||
|
cached: CommandPaletteEntry[] | undefined
|
||||||
|
} = { token: 0, inflight: undefined, cached: undefined }
|
||||||
|
|
||||||
onCleanup(() => abort?.abort())
|
return (text: string) => {
|
||||||
|
if (!text.trim()) {
|
||||||
return async (text: string): Promise<CommandPaletteEntry[]> => {
|
state.token += 1
|
||||||
const search = text.trim()
|
state.inflight = undefined
|
||||||
if (!search) {
|
state.cached = undefined
|
||||||
abort?.abort()
|
return [] as CommandPaletteEntry[]
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
abort?.abort()
|
if (state.cached) return state.cached
|
||||||
const current = new AbortController()
|
if (state.inflight) return state.inflight
|
||||||
abort = current
|
|
||||||
await new Promise<void>((resolve) => {
|
const current = state.token
|
||||||
const timer = setTimeout(resolve, 100)
|
const dirs = props.workspaces()
|
||||||
current.signal.addEventListener(
|
if (dirs.length === 0) return [] as CommandPaletteEntry[]
|
||||||
"abort",
|
|
||||||
() => {
|
state.inflight = Promise.all(
|
||||||
clearTimeout(timer)
|
dirs.map((directory) => {
|
||||||
resolve()
|
const description = props.label(directory)
|
||||||
},
|
|
||||||
{ once: true },
|
|
||||||
)
|
|
||||||
})
|
|
||||||
if (current.signal.aborted) return []
|
|
||||||
const opened = props.opened()
|
|
||||||
const openedByID = new Map(opened.flatMap((project) => (project.id ? [[project.id, project] as const] : [])))
|
|
||||||
const stored = props.stored().map((project) => ({ ...project, expanded: false }))
|
|
||||||
const storedByID = new Map(stored.map((project) => [project.id, project] as const))
|
|
||||||
return props
|
return props
|
||||||
.load(search, current.signal)
|
.load(directory)
|
||||||
.then((result) =>
|
.then((result) =>
|
||||||
(result.data ?? [])
|
(result.data ?? [])
|
||||||
.filter((session) => !session.time.archived)
|
.filter((session) => !!session?.id)
|
||||||
.map((session) => {
|
.map((session) => ({
|
||||||
const project =
|
id: session.id,
|
||||||
projectForSession(session, opened, openedByID) ?? projectForSession(session, stored, storedByID)
|
title: session.title ?? props.untitled(),
|
||||||
return {
|
description,
|
||||||
id: `session:${props.server}:${session.id}`,
|
directory,
|
||||||
type: "session" as const,
|
archived: session.time?.archived,
|
||||||
title: session.title || props.untitled(),
|
updated: session.time?.updated,
|
||||||
description: project ? displayName(project) : session.project?.name || getFilename(session.directory),
|
})),
|
||||||
category: props.category(),
|
)
|
||||||
directory: session.directory,
|
.catch(() => [] as SessionEntryInput[])
|
||||||
sessionID: session.id,
|
|
||||||
server: props.server,
|
|
||||||
project,
|
|
||||||
updated: session.time.updated,
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
.then((results) => {
|
||||||
|
if (state.token !== current) return [] as CommandPaletteEntry[]
|
||||||
|
const seen = new Set<string>()
|
||||||
|
const next = results
|
||||||
|
.flat()
|
||||||
|
.filter((item) => {
|
||||||
|
const key = `${item.directory}:${item.id}`
|
||||||
|
if (seen.has(key)) return false
|
||||||
|
seen.add(key)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
.map((item) => createSessionEntry(item, props.category()))
|
||||||
|
state.cached = next
|
||||||
|
return next
|
||||||
|
})
|
||||||
.catch(() => [] as CommandPaletteEntry[])
|
.catch(() => [] as CommandPaletteEntry[])
|
||||||
|
.finally(() => {
|
||||||
|
state.inflight = undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
return state.inflight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionEntryInput = {
|
||||||
|
directory: string
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
archived?: number
|
||||||
|
updated?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSessionEntry(input: SessionEntryInput, category: string): CommandPaletteEntry {
|
||||||
|
return {
|
||||||
|
id: `session:${input.directory}:${input.id}`,
|
||||||
|
type: "session",
|
||||||
|
title: input.title,
|
||||||
|
description: input.description,
|
||||||
|
category,
|
||||||
|
directory: input.directory,
|
||||||
|
sessionID: input.id,
|
||||||
|
archived: input.archived,
|
||||||
|
updated: input.updated,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,20 +5,13 @@ import { Dialog, DialogBody } from "@opencode-ai/ui/v2/dialog-v2"
|
|||||||
import { Icon } from "@opencode-ai/ui/v2/icon"
|
import { Icon } from "@opencode-ai/ui/v2/icon"
|
||||||
import { KeybindV2 } from "@opencode-ai/ui/v2/keybind-v2"
|
import { KeybindV2 } from "@opencode-ai/ui/v2/keybind-v2"
|
||||||
import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2"
|
import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2"
|
||||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
import { createEffect, createMemo, createResource, createSignal, For, Match, Show, Switch } from "solid-js"
|
||||||
import { createEffect, createMemo, createResource, createSignal, For, Match, onCleanup, Show, Switch } from "solid-js"
|
import { formatKeybindParts } from "@/context/command"
|
||||||
import { commandPaletteOptions, formatKeybindParts, useCommand } from "@/context/command"
|
|
||||||
import { useGlobal } from "@/context/global"
|
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { ServerConnection } from "@/context/server"
|
|
||||||
import { useTabs } from "@/context/tabs"
|
|
||||||
import { SessionTabAvatar } from "@/pages/layout/session-tab-avatar"
|
|
||||||
import { getRelativeTime } from "@/utils/time"
|
import { getRelativeTime } from "@/utils/time"
|
||||||
import {
|
import {
|
||||||
createCommandPaletteCommandEntry,
|
|
||||||
createCommandPaletteFileEntry,
|
createCommandPaletteFileEntry,
|
||||||
createCommandPaletteModel,
|
createCommandPaletteModel,
|
||||||
createServerSessionEntries,
|
|
||||||
uniqueCommandPaletteEntries,
|
uniqueCommandPaletteEntries,
|
||||||
type CommandPaletteEntry,
|
type CommandPaletteEntry,
|
||||||
} from "./command-palette"
|
} from "./command-palette"
|
||||||
@@ -37,6 +30,9 @@ function matchesEntry(entry: CommandPaletteEntry, query: string) {
|
|||||||
|
|
||||||
export function DialogCommandPaletteV2(props: { onOpenFile?: (path: string) => void }) {
|
export function DialogCommandPaletteV2(props: { onOpenFile?: (path: string) => void }) {
|
||||||
const palette = createCommandPaletteModel(props)
|
const palette = createCommandPaletteModel(props)
|
||||||
|
const [query, setQuery] = createSignal("")
|
||||||
|
const [active, setActive] = createSignal(0)
|
||||||
|
|
||||||
const loadItems = async (text: string) => {
|
const loadItems = async (text: string) => {
|
||||||
const q = text.trim()
|
const q = text.trim()
|
||||||
if (!q) return [...palette.preferredCommandEntries(), ...palette.recentFileEntries()]
|
if (!q) return [...palette.preferredCommandEntries(), ...palette.recentFileEntries()]
|
||||||
@@ -45,105 +41,16 @@ export function DialogCommandPaletteV2(props: { onOpenFile?: (path: string) => v
|
|||||||
const category = palette.language.t("palette.group.files")
|
const category = palette.language.t("palette.group.files")
|
||||||
return [
|
return [
|
||||||
...palette.commandEntries().filter((entry) => matchesEntry(entry, q)),
|
...palette.commandEntries().filter((entry) => matchesEntry(entry, q)),
|
||||||
...nextSessions,
|
...nextSessions.filter((entry) => matchesEntry(entry, q)),
|
||||||
...files.map((path) => createCommandPaletteFileEntry(path, category)),
|
...files.map((path) => createCommandPaletteFileEntry(path, category)),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const [entries] = createResource(query, loadItems, { initialValue: [] as CommandPaletteEntry[] })
|
||||||
<CommandPaletteView
|
|
||||||
placeholder={palette.language.t("palette.search.placeholder")}
|
|
||||||
loadItems={loadItems}
|
|
||||||
highlight={palette.highlight}
|
|
||||||
select={palette.select}
|
|
||||||
close={palette.close}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function DialogHomeCommandPaletteV2(props: {
|
|
||||||
server: ServerConnection.Any
|
|
||||||
onSelectSession: (entry: CommandPaletteEntry) => void
|
|
||||||
}) {
|
|
||||||
const command = useCommand()
|
|
||||||
const dialog = useDialog()
|
|
||||||
const global = useGlobal()
|
|
||||||
const language = useLanguage()
|
|
||||||
const serverCtx = global.ensureServerCtx(props.server)
|
|
||||||
const state = { cleanup: undefined as (() => void) | void, committed: false }
|
|
||||||
const commandEntries = createMemo(() => {
|
|
||||||
const category = language.t("palette.group.commands")
|
|
||||||
return commandPaletteOptions(command.options).map((option) => createCommandPaletteCommandEntry(option, category))
|
|
||||||
})
|
|
||||||
const sessions = createServerSessionEntries({
|
|
||||||
server: ServerConnection.key(props.server),
|
|
||||||
opened: serverCtx.projects.list,
|
|
||||||
stored: () => serverCtx.sync.data.project,
|
|
||||||
load: (search, signal) =>
|
|
||||||
serverCtx.sdk.client.experimental.session.list({ roots: true, search, limit: 50 }, { signal }),
|
|
||||||
untitled: () => language.t("command.session.new"),
|
|
||||||
category: () => language.t("command.category.session"),
|
|
||||||
})
|
|
||||||
|
|
||||||
const highlight = (item: CommandPaletteEntry | undefined) => {
|
|
||||||
state.cleanup?.()
|
|
||||||
state.cleanup = undefined
|
|
||||||
if (item?.type !== "command") return
|
|
||||||
state.cleanup = item.option?.onHighlight?.()
|
|
||||||
}
|
|
||||||
const select = (item: CommandPaletteEntry | undefined) => {
|
|
||||||
if (!item) return
|
|
||||||
state.committed = true
|
|
||||||
state.cleanup = undefined
|
|
||||||
dialog.close()
|
|
||||||
if (item.type === "command") {
|
|
||||||
item.option?.onSelect?.("palette")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (item.type === "session") props.onSelectSession(item)
|
|
||||||
}
|
|
||||||
const loadItems = async (text: string) => {
|
|
||||||
const query = text.trim()
|
|
||||||
if (!query) return commandEntries().slice(0, 5)
|
|
||||||
return [...commandEntries().filter((entry) => matchesEntry(entry, query)), ...(await sessions(query))]
|
|
||||||
}
|
|
||||||
|
|
||||||
onCleanup(() => {
|
|
||||||
if (state.committed) return
|
|
||||||
state.cleanup?.()
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CommandPaletteView
|
|
||||||
placeholder={language.t("palette.search.placeholder.home")}
|
|
||||||
loadItems={loadItems}
|
|
||||||
highlight={highlight}
|
|
||||||
select={select}
|
|
||||||
close={() => dialog.close()}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function CommandPaletteView(props: {
|
|
||||||
placeholder: string
|
|
||||||
loadItems: (text: string) => CommandPaletteEntry[] | Promise<CommandPaletteEntry[]>
|
|
||||||
highlight: (item: CommandPaletteEntry | undefined) => void
|
|
||||||
select: (item: CommandPaletteEntry | undefined) => void
|
|
||||||
close: () => void
|
|
||||||
}) {
|
|
||||||
const language = useLanguage()
|
|
||||||
const tabs = useTabs()
|
|
||||||
const [query, setQuery] = createSignal("")
|
|
||||||
const [active, setActive] = createSignal(0)
|
|
||||||
|
|
||||||
const [entries] = createResource(query, props.loadItems, { initialValue: [] as CommandPaletteEntry[] })
|
|
||||||
// Render stale results while a new query loads to avoid flashing "Loading" per keystroke.
|
// Render stale results while a new query loads to avoid flashing "Loading" per keystroke.
|
||||||
const visibleEntries = createMemo(() => uniqueCommandPaletteEntries(entries.latest ?? []))
|
const visibleEntries = createMemo(() => uniqueCommandPaletteEntries(entries.latest ?? []))
|
||||||
const groupedEntries = createMemo(() => groups(visibleEntries()))
|
const groupedEntries = createMemo(() => groups(visibleEntries()))
|
||||||
const activeEntry = createMemo(() => visibleEntries()[active()])
|
const activeEntry = createMemo(() => visibleEntries()[active()])
|
||||||
const openSessions = createMemo(
|
|
||||||
() => new Set(tabs.store.flatMap((tab) => (tab.type === "session" ? [`${tab.server}\0${tab.sessionId}`] : []))),
|
|
||||||
)
|
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
query()
|
query()
|
||||||
@@ -152,7 +59,7 @@ function CommandPaletteView(props: {
|
|||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
props.highlight(activeEntry())
|
palette.highlight(activeEntry())
|
||||||
})
|
})
|
||||||
|
|
||||||
let resultsRef: HTMLDivElement | undefined
|
let resultsRef: HTMLDivElement | undefined
|
||||||
@@ -179,12 +86,12 @@ function CommandPaletteView(props: {
|
|||||||
}
|
}
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
props.select(activeEntry())
|
palette.select(activeEntry())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (event.key === "Escape") {
|
if (event.key === "Escape") {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
props.close()
|
palette.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +105,7 @@ function CommandPaletteView(props: {
|
|||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
spellcheck={false}
|
spellcheck={false}
|
||||||
appearance="large"
|
appearance="large"
|
||||||
placeholder={props.placeholder}
|
placeholder={palette.language.t("palette.search.placeholder")}
|
||||||
leadingIcon={<Icon name="magnifying-glass" />}
|
leadingIcon={<Icon name="magnifying-glass" />}
|
||||||
onInput={(event) => setQuery(event.currentTarget.value)}
|
onInput={(event) => setQuery(event.currentTarget.value)}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
@@ -210,7 +117,7 @@ function CommandPaletteView(props: {
|
|||||||
when={visibleEntries().length > 0}
|
when={visibleEntries().length > 0}
|
||||||
fallback={
|
fallback={
|
||||||
<div class="command-palette-v2-state">
|
<div class="command-palette-v2-state">
|
||||||
{entries.loading ? language.t("common.loading") : language.t("palette.empty")}
|
{entries.loading ? palette.language.t("common.loading") : palette.language.t("palette.empty")}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -225,14 +132,9 @@ function CommandPaletteView(props: {
|
|||||||
<PaletteRow
|
<PaletteRow
|
||||||
item={item}
|
item={item}
|
||||||
active={activeEntry()?.id === item.id}
|
active={activeEntry()?.id === item.id}
|
||||||
language={language}
|
language={palette.language}
|
||||||
sessionOpen={
|
|
||||||
item.server && item.sessionID
|
|
||||||
? openSessions().has(`${item.server}\0${item.sessionID}`)
|
|
||||||
: false
|
|
||||||
}
|
|
||||||
onActive={() => setActive(visibleEntries().findIndex((entry) => entry.id === item.id))}
|
onActive={() => setActive(visibleEntries().findIndex((entry) => entry.id === item.id))}
|
||||||
onSelect={() => props.select(item)}
|
onSelect={() => palette.select(item)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
@@ -251,19 +153,13 @@ function PaletteRow(props: {
|
|||||||
item: CommandPaletteEntry
|
item: CommandPaletteEntry
|
||||||
active: boolean
|
active: boolean
|
||||||
language: ReturnType<typeof useLanguage>
|
language: ReturnType<typeof useLanguage>
|
||||||
sessionOpen: boolean
|
|
||||||
onActive: () => void
|
onActive: () => void
|
||||||
onSelect: () => void
|
onSelect: () => void
|
||||||
}) {
|
}) {
|
||||||
const session = () =>
|
|
||||||
props.item.server && props.item.directory && props.item.sessionID
|
|
||||||
? { server: props.item.server, directory: props.item.directory, sessionID: props.item.sessionID }
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="command-palette-v2-row group"
|
class="command-palette-v2-row"
|
||||||
role="option"
|
role="option"
|
||||||
aria-selected={props.active}
|
aria-selected={props.active}
|
||||||
data-active={props.active ? "" : undefined}
|
data-active={props.active ? "" : undefined}
|
||||||
@@ -301,25 +197,7 @@ function PaletteRow(props: {
|
|||||||
</Match>
|
</Match>
|
||||||
<Match when={props.item.type === "session"}>
|
<Match when={props.item.type === "session"}>
|
||||||
<div class="command-palette-v2-row-main">
|
<div class="command-palette-v2-row-main">
|
||||||
<div class="relative shrink-0">
|
<Icon name="status" class="command-palette-v2-row-icon" />
|
||||||
<Show when={props.sessionOpen}>
|
|
||||||
<span
|
|
||||||
aria-hidden="true"
|
|
||||||
class="pointer-events-none absolute top-1/2 h-3 w-0.5 -translate-y-1/2 rounded-[2px] bg-v2-background-bg-layer-04"
|
|
||||||
style={{ right: "calc(100% + 4px)" }}
|
|
||||||
/>
|
|
||||||
</Show>
|
|
||||||
<Show when={session()}>
|
|
||||||
{(session) => (
|
|
||||||
<SessionTabAvatar
|
|
||||||
project={props.item.project}
|
|
||||||
directory={session().directory}
|
|
||||||
sessionId={session().sessionID}
|
|
||||||
server={session().server}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
<div class="command-palette-v2-row-text">
|
<div class="command-palette-v2-row-text">
|
||||||
<span class="command-palette-v2-title" classList={{ "opacity-70": !!props.item.archived }}>
|
<span class="command-palette-v2-title" classList={{ "opacity-70": !!props.item.archived }}>
|
||||||
{props.item.title}
|
{props.item.title}
|
||||||
|
|||||||
@@ -8,20 +8,61 @@ import introducingTabsVideo from "@/assets/help/introducing-tabs.mp4"
|
|||||||
import homeImage from "@/assets/help/home.png"
|
import homeImage from "@/assets/help/home.png"
|
||||||
import tabsImage from "@/assets/help/tabs.png"
|
import tabsImage from "@/assets/help/tabs.png"
|
||||||
|
|
||||||
|
const helpIcon = (
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
aria-hidden="true"
|
||||||
|
data-slot="icon-svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.94235 10.5714V10.4854C6.94617 9.76302 7.01879 9.18777 7.16022 8.75968C7.30546 8.33158 7.50804 7.98567 7.76796 7.72193C8.02787 7.45819 8.34321 7.21548 8.71397 6.99379C8.93948 6.85619 9.14206 6.69374 9.32171 6.50645C9.50518 6.31916 9.64851 6.10511 9.75171 5.86431C9.85874 5.62351 9.91225 5.35404 9.91225 5.0559C9.91225 4.69661 9.82625 4.38509 9.65424 4.12136C9.48607 3.85762 9.26055 3.65504 8.9777 3.51362C8.69486 3.36837 8.38143 3.29575 8.03743 3.29575C7.73165 3.29575 7.43733 3.35882 7.15448 3.48495C6.87546 3.61108 6.6423 3.80984 6.45501 4.08122C6.26772 4.3526 6.15878 4.70425 6.12821 5.13617H4.56299C4.59357 4.47109 4.76557 3.9054 5.07899 3.43908C5.39242 2.96894 5.80522 2.61156 6.31741 2.36694C6.83341 2.12231 7.40675 2 8.03743 2C8.72161 2 9.31789 2.13378 9.82625 2.40134C10.3384 2.66507 10.734 3.0301 11.0131 3.49642C11.2959 3.96273 11.4373 4.49976 11.4373 5.1075C11.4373 5.53177 11.3724 5.914 11.2424 6.25418C11.1124 6.59436 10.9251 6.89823 10.6805 7.16579C10.4397 7.43335 10.1492 7.67033 9.80905 7.87673C9.48033 8.08313 9.21468 8.301 9.0121 8.53034C8.80952 8.75585 8.66237 9.02341 8.57063 9.33302C8.4789 9.64262 8.42921 10.0268 8.42156 10.4854V10.5714H6.94235ZM7.72782 14C7.43351 14 7.17933 13.8949 6.96528 13.6847C6.75506 13.4744 6.64994 13.2203 6.64994 12.9221C6.64994 12.6278 6.75506 12.3755 6.96528 12.1653C7.17933 11.9551 7.43351 11.85 7.72782 11.85C8.02214 11.85 8.27441 11.9551 8.48463 12.1653C8.69868 12.3755 8.8057 12.6278 8.8057 12.9221C8.8057 13.1209 8.75601 13.3024 8.65663 13.4668C8.55726 13.6273 8.4273 13.7573 8.26676 13.8567C8.10623 13.9522 7.92658 14 7.72782 14Z"
|
||||||
|
fill="var(--v2-icon-icon-base)"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const triggerClass =
|
||||||
|
"size-7 !rounded-full shrink-0 bg-v2-background-bg-base shadow-[var(--v2-elevation-button-neutral)]"
|
||||||
|
|
||||||
// TODO: wire to changelog / seen-state when available
|
// TODO: wire to changelog / seen-state when available
|
||||||
const showPopover = () => true
|
const showPopover = () => true
|
||||||
|
|
||||||
|
export function HelpButton() {
|
||||||
|
if (import.meta.env.VITE_OPENCODE_CHANNEL !== "dev") return null
|
||||||
|
|
||||||
|
const platform = usePlatform()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
href="https://opencode.ai"
|
||||||
|
aria-label="Open the OpenCode website"
|
||||||
|
data-component="icon-button-v2"
|
||||||
|
data-size="large"
|
||||||
|
class={`${triggerClass} fixed bottom-5 right-5 z-50 flex items-center justify-center`}
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
platform.openLink(event.currentTarget.href)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{helpIcon}
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// can remove this after the tabs rollout has been out for a while
|
// can remove this after the tabs rollout has been out for a while
|
||||||
export function TabsInfoPopup() {
|
export function TabsInfoPopup() {
|
||||||
const settings = useSettings()
|
const settings = useSettings()
|
||||||
const platform = usePlatform()
|
|
||||||
const [drawerOpen, setDrawerOpen] = createSignal(false)
|
const [drawerOpen, setDrawerOpen] = createSignal(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer open={drawerOpen()} onOpenChange={setDrawerOpen} side="right">
|
<Drawer open={drawerOpen()} onOpenChange={setDrawerOpen} side="right">
|
||||||
<Show when={settings.general.shouldDisplayTabsToast()}>
|
<Show when={settings.general.shouldDisplayTabsToast()}>
|
||||||
<div
|
<div
|
||||||
class="fixed bottom-5 right-5 z-50 h-[240px] w-[192px] rounded-[8px] bg-v2-background-bg-base p-1 shadow-[var(--v2-elevation-floating)]"
|
class="fixed bottom-14 right-5 z-50 h-[240px] w-[192px] rounded-[8px] bg-v2-background-bg-base p-1 shadow-[var(--v2-elevation-floating)]"
|
||||||
aria-label="Introducing Tabs. Organize your work and active sessions with tabs"
|
aria-label="Introducing Tabs. Organize your work and active sessions with tabs"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
@@ -73,9 +114,8 @@ export function TabsInfoPopup() {
|
|||||||
<DrawerContent>
|
<DrawerContent>
|
||||||
<div class="flex h-[52px] w-full shrink-0 items-center gap-4 self-stretch border-b border-v2-border-border-muted p-4">
|
<div class="flex h-[52px] w-full shrink-0 items-center gap-4 self-stretch border-b border-v2-border-border-muted p-4">
|
||||||
<p class="min-h-0 min-w-0 flex-1 text-[13px] font-[530] leading-5 tracking-[-0.04px] tabular-nums text-v2-text-text-muted">
|
<p class="min-h-0 min-w-0 flex-1 text-[13px] font-[530] leading-5 tracking-[-0.04px] tabular-nums text-v2-text-text-muted">
|
||||||
July 14
|
June 16
|
||||||
</p>
|
</p>
|
||||||
<Show when={platform.platform !== "desktop" || platform.os !== "windows"}>
|
|
||||||
<DrawerClose
|
<DrawerClose
|
||||||
as={IconButtonV2}
|
as={IconButtonV2}
|
||||||
type="button"
|
type="button"
|
||||||
@@ -84,7 +124,6 @@ export function TabsInfoPopup() {
|
|||||||
aria-label="Close"
|
aria-label="Close"
|
||||||
icon={<IconV2 name="xmark-small" />}
|
icon={<IconV2 name="xmark-small" />}
|
||||||
/>
|
/>
|
||||||
</Show>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="relative flex min-h-0 w-full flex-1 flex-col items-start gap-6 overflow-y-auto p-8">
|
<div class="relative flex min-h-0 w-full flex-1 flex-col items-start gap-6 overflow-y-auto p-8">
|
||||||
<p class="w-full shrink-0 self-stretch text-[21px] font-[610] leading-6 tracking-[-0.37px] tabular-nums text-v2-text-text-base">
|
<p class="w-full shrink-0 self-stretch text-[21px] font-[610] leading-6 tracking-[-0.37px] tabular-nums text-v2-text-text-base">
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2"
|
|||||||
import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2"
|
import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2"
|
||||||
import { showToast } from "@/utils/toast"
|
import { showToast } from "@/utils/toast"
|
||||||
import fuzzysort from "fuzzysort"
|
import fuzzysort from "fuzzysort"
|
||||||
import { DEFAULT_PALETTE_KEYBIND, formatKeybind, parseKeybind, useCommand } from "@/context/command"
|
import { formatKeybind, parseKeybind, useCommand } from "@/context/command"
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { useSettings } from "@/context/settings"
|
import { useSettings } from "@/context/settings"
|
||||||
import { SettingsList } from "./settings-list"
|
import { SettingsList } from "./settings-list"
|
||||||
@@ -20,6 +20,7 @@ const IconV2 = lazy(() => import("@opencode-ai/ui/v2/icon").then((module) => ({
|
|||||||
|
|
||||||
const IS_MAC = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform)
|
const IS_MAC = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform)
|
||||||
const PALETTE_ID = "command.palette"
|
const PALETTE_ID = "command.palette"
|
||||||
|
const DEFAULT_PALETTE_KEYBIND = "mod+shift+p"
|
||||||
|
|
||||||
type KeybindGroup = "General" | "Session" | "Navigation" | "Model and agent" | "Terminal" | "Prompt"
|
type KeybindGroup = "General" | "Session" | "Navigation" | "Model and agent" | "Terminal" | "Prompt"
|
||||||
|
|
||||||
|
|||||||
@@ -371,7 +371,7 @@
|
|||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-v2-models {
|
.settings-v2-tab-body.settings-v2-models {
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -392,7 +392,7 @@ export function Titlebar(props: { update?: TitlebarUpdate }) {
|
|||||||
id: "tab.new",
|
id: "tab.new",
|
||||||
category: "tab",
|
category: "tab",
|
||||||
title: language.t("command.session.new"),
|
title: language.t("command.session.new"),
|
||||||
keybind: "mod+t,mod+n",
|
keybind: "mod+t",
|
||||||
hidden: true,
|
hidden: true,
|
||||||
onSelect: openNewTab,
|
onSelect: openNewTab,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,19 +1,5 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { commandPaletteOptions, resolveKeybindOption, upsertCommandRegistration, type CommandOption } from "./command"
|
import { resolveKeybindOption, upsertCommandRegistration } from "./command"
|
||||||
|
|
||||||
const paletteOptions: CommandOption[] = [
|
|
||||||
{ id: "settings.open", title: "Open settings" },
|
|
||||||
{ id: "session.undo", title: "Undo" },
|
|
||||||
{ id: "file.open", title: "Open file" },
|
|
||||||
{ id: "hidden", title: "Hidden", hidden: true },
|
|
||||||
{ id: "disabled", title: "Disabled", disabled: true },
|
|
||||||
]
|
|
||||||
|
|
||||||
describe("commandPaletteOptions", () => {
|
|
||||||
test("keeps visible enabled commands", () => {
|
|
||||||
expect(commandPaletteOptions(paletteOptions).map((option) => option.id)).toEqual(["settings.open", "session.undo"])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("upsertCommandRegistration", () => {
|
describe("upsertCommandRegistration", () => {
|
||||||
test("replaces keyed registrations", () => {
|
test("replaces keyed registrations", () => {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { Persist, persisted } from "@/utils/persist"
|
|||||||
const IS_MAC = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform)
|
const IS_MAC = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform)
|
||||||
|
|
||||||
const PALETTE_ID = "command.palette"
|
const PALETTE_ID = "command.palette"
|
||||||
export const DEFAULT_PALETTE_KEYBIND = "mod+k,mod+shift+p"
|
const DEFAULT_PALETTE_KEYBIND = "mod+shift+p"
|
||||||
const SUGGESTED_PREFIX = "suggested."
|
const SUGGESTED_PREFIX = "suggested."
|
||||||
const EDITABLE_KEYBIND_IDS = new Set(["terminal.toggle", "terminal.new", "file.attach"])
|
const EDITABLE_KEYBIND_IDS = new Set(["terminal.toggle", "terminal.new", "file.attach"])
|
||||||
|
|
||||||
@@ -87,13 +87,6 @@ export interface CommandOption {
|
|||||||
onHighlight?: () => (() => void) | void
|
onHighlight?: () => (() => void) | void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function commandPaletteOptions(options: CommandOption[]) {
|
|
||||||
return options.filter(
|
|
||||||
(option) =>
|
|
||||||
!option.disabled && !option.hidden && !option.id.startsWith(SUGGESTED_PREFIX) && option.id !== "file.open",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resolveKeybindOption(candidates: CommandOption[] | undefined, event: KeyboardEvent) {
|
export function resolveKeybindOption(candidates: CommandOption[] | undefined, event: KeyboardEvent) {
|
||||||
return candidates?.find((option) => option.when?.(event)) ?? candidates?.find((option) => !option.when)
|
return candidates?.find((option) => option.when?.(event)) ?? candidates?.find((option) => !option.when)
|
||||||
}
|
}
|
||||||
@@ -382,7 +375,7 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex
|
|||||||
}
|
}
|
||||||
|
|
||||||
const showPalette = () => {
|
const showPalette = () => {
|
||||||
run(PALETTE_ID, "palette")
|
run("file.open", "palette")
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleKeyDown = (event: KeyboardEvent) => {
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
|
||||||
import { hasCustomAgent, resolveAgent } from "./local-agent"
|
|
||||||
|
|
||||||
describe("hasCustomAgent", () => {
|
|
||||||
test("detects explicitly custom agents", () => {
|
|
||||||
expect(hasCustomAgent([{ native: true }, { native: false }])).toBe(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("ignores built-in and unclassified agents", () => {
|
|
||||||
expect(hasCustomAgent([{ native: true }, {}])).toBe(false)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("resolveAgent", () => {
|
|
||||||
const agents = [{ name: "plan" }, { name: "build" }, { name: "custom" }]
|
|
||||||
|
|
||||||
test("uses the requested available agent", () => {
|
|
||||||
expect(resolveAgent(agents, "custom")?.name).toBe("custom")
|
|
||||||
})
|
|
||||||
|
|
||||||
test("defaults to build", () => {
|
|
||||||
expect(resolveAgent(agents)?.name).toBe("build")
|
|
||||||
expect(resolveAgent(agents, "missing")?.name).toBe("build")
|
|
||||||
})
|
|
||||||
|
|
||||||
test("uses the first agent when build is unavailable", () => {
|
|
||||||
expect(resolveAgent([{ name: "custom" }], "missing")?.name).toBe("custom")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
export function hasCustomAgent(items: Array<{ native?: boolean }>) {
|
|
||||||
return items.some((item) => item.native === false)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resolveAgent<T extends { name: string }>(items: T[], name?: string) {
|
|
||||||
return items.find((item) => item.name === name) ?? items.find((item) => item.name === "build") ?? items[0]
|
|
||||||
}
|
|
||||||
@@ -4,10 +4,8 @@ import { useParams } from "@solidjs/router"
|
|||||||
import { batch, createEffect, createMemo, startTransition } from "solid-js"
|
import { batch, createEffect, createMemo, startTransition } from "solid-js"
|
||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
import { useModels } from "@/context/models"
|
import { useModels } from "@/context/models"
|
||||||
import { useSettings } from "@/context/settings"
|
|
||||||
import { useProviders } from "@/hooks/use-providers"
|
import { useProviders } from "@/hooks/use-providers"
|
||||||
import { Persist, persisted } from "@/utils/persist"
|
import { Persist, persisted } from "@/utils/persist"
|
||||||
import { hasCustomAgent, resolveAgent } from "./local-agent"
|
|
||||||
import { cycleModelVariant, getConfiguredAgentVariant, resolveModelVariant } from "./model-variant"
|
import { cycleModelVariant, getConfiguredAgentVariant, resolveModelVariant } from "./model-variant"
|
||||||
import { useSDK } from "./sdk"
|
import { useSDK } from "./sdk"
|
||||||
import { useSync } from "./sync"
|
import { useSync } from "./sync"
|
||||||
@@ -64,11 +62,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
|||||||
const serverSDK = useServerSDK()
|
const serverSDK = useServerSDK()
|
||||||
const providers = useProviders(() => sdk().directory)
|
const providers = useProviders(() => sdk().directory)
|
||||||
const models = useModels()
|
const models = useModels()
|
||||||
const settings = useSettings()
|
|
||||||
|
|
||||||
const id = createMemo(() => params.id || undefined)
|
const id = createMemo(() => params.id || undefined)
|
||||||
const list = createMemo(() => sync().data.agent.filter((item) => item.mode !== "subagent" && !item.hidden))
|
const list = createMemo(() => sync().data.agent.filter((item) => item.mode !== "subagent" && !item.hidden))
|
||||||
const agentsVisible = createMemo(() => settings.visibility.customAgents() || hasCustomAgent(list()))
|
|
||||||
const connected = createMemo(() => new Set(providers.connected().map((item) => item.id)))
|
const connected = createMemo(() => new Set(providers.connected().map((item) => item.id)))
|
||||||
|
|
||||||
const [saved, setSaved, , savedReady] = persisted(
|
const [saved, setSaved, , savedReady] = persisted(
|
||||||
@@ -111,7 +107,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pickAgent = (name: string | undefined) => {
|
const pickAgent = (name: string | undefined) => {
|
||||||
return resolveAgent(list(), name)
|
const items = list()
|
||||||
|
if (items.length === 0) return
|
||||||
|
return items.find((item) => item.name === name) ?? items[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
@@ -182,9 +180,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
|||||||
|
|
||||||
const agent = {
|
const agent = {
|
||||||
list,
|
list,
|
||||||
visible: agentsVisible,
|
|
||||||
current() {
|
current() {
|
||||||
return pickAgent(agentsVisible() ? (scope()?.agent ?? store.current) : "build")
|
return pickAgent(scope()?.agent ?? store.current)
|
||||||
},
|
},
|
||||||
set(name: string | undefined) {
|
set(name: string | undefined) {
|
||||||
const item = pickAgent(name)
|
const item = pickAgent(name)
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "إلغاء مشاركة الجلسة",
|
"command.session.unshare": "إلغاء مشاركة الجلسة",
|
||||||
"command.session.unshare.description": "إيقاف مشاركة هذه الجلسة",
|
"command.session.unshare.description": "إيقاف مشاركة هذه الجلسة",
|
||||||
"palette.search.placeholder": "البحث في الملفات والأوامر والجلسات",
|
"palette.search.placeholder": "البحث في الملفات والأوامر والجلسات",
|
||||||
"palette.search.placeholder.home": "البحث في الأوامر والجلسات",
|
|
||||||
"palette.empty": "لا توجد نتائج",
|
"palette.empty": "لا توجد نتائج",
|
||||||
"palette.group.commands": "الأوامر",
|
"palette.group.commands": "الأوامر",
|
||||||
"palette.group.files": "الملفات",
|
"palette.group.files": "الملفات",
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "Parar de compartilhar sessão",
|
"command.session.unshare": "Parar de compartilhar sessão",
|
||||||
"command.session.unshare.description": "Parar de compartilhar esta sessão",
|
"command.session.unshare.description": "Parar de compartilhar esta sessão",
|
||||||
"palette.search.placeholder": "Buscar arquivos, comandos e sessões",
|
"palette.search.placeholder": "Buscar arquivos, comandos e sessões",
|
||||||
"palette.search.placeholder.home": "Buscar comandos e sessões",
|
|
||||||
"palette.empty": "Nenhum resultado encontrado",
|
"palette.empty": "Nenhum resultado encontrado",
|
||||||
"palette.group.commands": "Comandos",
|
"palette.group.commands": "Comandos",
|
||||||
"palette.group.files": "Arquivos",
|
"palette.group.files": "Arquivos",
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ export const dict = {
|
|||||||
"command.session.unshare.description": "Zaustavi dijeljenje ove sesije",
|
"command.session.unshare.description": "Zaustavi dijeljenje ove sesije",
|
||||||
|
|
||||||
"palette.search.placeholder": "Pretraži datoteke, komande i sesije",
|
"palette.search.placeholder": "Pretraži datoteke, komande i sesije",
|
||||||
"palette.search.placeholder.home": "Pretraži komande i sesije",
|
|
||||||
"palette.empty": "Nema rezultata",
|
"palette.empty": "Nema rezultata",
|
||||||
"palette.group.commands": "Komande",
|
"palette.group.commands": "Komande",
|
||||||
"palette.group.files": "Datoteke",
|
"palette.group.files": "Datoteke",
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ export const dict = {
|
|||||||
"command.session.unshare.description": "Stop med at dele denne session",
|
"command.session.unshare.description": "Stop med at dele denne session",
|
||||||
|
|
||||||
"palette.search.placeholder": "Søg i filer, kommandoer og sessioner",
|
"palette.search.placeholder": "Søg i filer, kommandoer og sessioner",
|
||||||
"palette.search.placeholder.home": "Søg i kommandoer og sessioner",
|
|
||||||
"palette.empty": "Ingen resultater fundet",
|
"palette.empty": "Ingen resultater fundet",
|
||||||
"palette.group.commands": "Kommandoer",
|
"palette.group.commands": "Kommandoer",
|
||||||
"palette.group.files": "Filer",
|
"palette.group.files": "Filer",
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "Teilen der Sitzung aufheben",
|
"command.session.unshare": "Teilen der Sitzung aufheben",
|
||||||
"command.session.unshare.description": "Teilen dieser Sitzung beenden",
|
"command.session.unshare.description": "Teilen dieser Sitzung beenden",
|
||||||
"palette.search.placeholder": "Dateien, Befehle und Sitzungen durchsuchen",
|
"palette.search.placeholder": "Dateien, Befehle und Sitzungen durchsuchen",
|
||||||
"palette.search.placeholder.home": "Befehle und Sitzungen durchsuchen",
|
|
||||||
"palette.empty": "Keine Ergebnisse gefunden",
|
"palette.empty": "Keine Ergebnisse gefunden",
|
||||||
"palette.group.commands": "Befehle",
|
"palette.group.commands": "Befehle",
|
||||||
"palette.group.files": "Dateien",
|
"palette.group.files": "Dateien",
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ export const dict = {
|
|||||||
"command.session.unshare.description": "Stop sharing this session",
|
"command.session.unshare.description": "Stop sharing this session",
|
||||||
|
|
||||||
"palette.search.placeholder": "Search files, commands, and sessions",
|
"palette.search.placeholder": "Search files, commands, and sessions",
|
||||||
"palette.search.placeholder.home": "Search commands and sessions",
|
|
||||||
"palette.empty": "No results found",
|
"palette.empty": "No results found",
|
||||||
"palette.group.commands": "Commands",
|
"palette.group.commands": "Commands",
|
||||||
"palette.group.files": "Files",
|
"palette.group.files": "Files",
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ export const dict = {
|
|||||||
"command.session.unshare.description": "Dejar de compartir esta sesión",
|
"command.session.unshare.description": "Dejar de compartir esta sesión",
|
||||||
|
|
||||||
"palette.search.placeholder": "Buscar archivos, comandos y sesiones",
|
"palette.search.placeholder": "Buscar archivos, comandos y sesiones",
|
||||||
"palette.search.placeholder.home": "Buscar comandos y sesiones",
|
|
||||||
"palette.empty": "No se encontraron resultados",
|
"palette.empty": "No se encontraron resultados",
|
||||||
"palette.group.commands": "Comandos",
|
"palette.group.commands": "Comandos",
|
||||||
"palette.group.files": "Archivos",
|
"palette.group.files": "Archivos",
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "Ne plus partager la session",
|
"command.session.unshare": "Ne plus partager la session",
|
||||||
"command.session.unshare.description": "Arrêter de partager cette session",
|
"command.session.unshare.description": "Arrêter de partager cette session",
|
||||||
"palette.search.placeholder": "Rechercher des fichiers, des commandes et des sessions",
|
"palette.search.placeholder": "Rechercher des fichiers, des commandes et des sessions",
|
||||||
"palette.search.placeholder.home": "Rechercher des commandes et des sessions",
|
|
||||||
"palette.empty": "Aucun résultat trouvé",
|
"palette.empty": "Aucun résultat trouvé",
|
||||||
"palette.group.commands": "Commandes",
|
"palette.group.commands": "Commandes",
|
||||||
"palette.group.files": "Fichiers",
|
"palette.group.files": "Fichiers",
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "セッションの共有を停止",
|
"command.session.unshare": "セッションの共有を停止",
|
||||||
"command.session.unshare.description": "このセッションの共有を停止",
|
"command.session.unshare.description": "このセッションの共有を停止",
|
||||||
"palette.search.placeholder": "ファイル、コマンド、セッションを検索",
|
"palette.search.placeholder": "ファイル、コマンド、セッションを検索",
|
||||||
"palette.search.placeholder.home": "コマンドとセッションを検索",
|
|
||||||
"palette.empty": "結果が見つかりません",
|
"palette.empty": "結果が見つかりません",
|
||||||
"palette.group.commands": "コマンド",
|
"palette.group.commands": "コマンド",
|
||||||
"palette.group.files": "ファイル",
|
"palette.group.files": "ファイル",
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "세션 공유 중지",
|
"command.session.unshare": "세션 공유 중지",
|
||||||
"command.session.unshare.description": "이 세션 공유 중지",
|
"command.session.unshare.description": "이 세션 공유 중지",
|
||||||
"palette.search.placeholder": "파일, 명령어 및 세션 검색",
|
"palette.search.placeholder": "파일, 명령어 및 세션 검색",
|
||||||
"palette.search.placeholder.home": "명령어 및 세션 검색",
|
|
||||||
"palette.empty": "결과 없음",
|
"palette.empty": "결과 없음",
|
||||||
"palette.group.commands": "명령어",
|
"palette.group.commands": "명령어",
|
||||||
"palette.group.files": "파일",
|
"palette.group.files": "파일",
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ export const dict = {
|
|||||||
"command.session.unshare.description": "Slutt å dele denne sesjonen",
|
"command.session.unshare.description": "Slutt å dele denne sesjonen",
|
||||||
|
|
||||||
"palette.search.placeholder": "Søk i filer, kommandoer og sesjoner",
|
"palette.search.placeholder": "Søk i filer, kommandoer og sesjoner",
|
||||||
"palette.search.placeholder.home": "Søk i kommandoer og sesjoner",
|
|
||||||
"palette.empty": "Ingen resultater funnet",
|
"palette.empty": "Ingen resultater funnet",
|
||||||
"palette.group.commands": "Kommandoer",
|
"palette.group.commands": "Kommandoer",
|
||||||
"palette.group.files": "Filer",
|
"palette.group.files": "Filer",
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "Przestań udostępniać sesję",
|
"command.session.unshare": "Przestań udostępniać sesję",
|
||||||
"command.session.unshare.description": "Zatrzymaj udostępnianie tej sesji",
|
"command.session.unshare.description": "Zatrzymaj udostępnianie tej sesji",
|
||||||
"palette.search.placeholder": "Szukaj plików, poleceń i sesji",
|
"palette.search.placeholder": "Szukaj plików, poleceń i sesji",
|
||||||
"palette.search.placeholder.home": "Szukaj poleceń i sesji",
|
|
||||||
"palette.empty": "Brak wyników",
|
"palette.empty": "Brak wyników",
|
||||||
"palette.group.commands": "Polecenia",
|
"palette.group.commands": "Polecenia",
|
||||||
"palette.group.files": "Pliki",
|
"palette.group.files": "Pliki",
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ export const dict = {
|
|||||||
"command.session.unshare.description": "Прекратить публикацию сессии",
|
"command.session.unshare.description": "Прекратить публикацию сессии",
|
||||||
|
|
||||||
"palette.search.placeholder": "Поиск файлов, команд и сессий",
|
"palette.search.placeholder": "Поиск файлов, команд и сессий",
|
||||||
"palette.search.placeholder.home": "Поиск команд и сессий",
|
|
||||||
"palette.empty": "Ничего не найдено",
|
"palette.empty": "Ничего не найдено",
|
||||||
"palette.group.commands": "Команды",
|
"palette.group.commands": "Команды",
|
||||||
"palette.group.files": "Файлы",
|
"palette.group.files": "Файлы",
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ export const dict = {
|
|||||||
"command.session.unshare.description": "หยุดการแชร์เซสชันนี้",
|
"command.session.unshare.description": "หยุดการแชร์เซสชันนี้",
|
||||||
|
|
||||||
"palette.search.placeholder": "ค้นหาไฟล์ คำสั่ง และเซสชัน",
|
"palette.search.placeholder": "ค้นหาไฟล์ คำสั่ง และเซสชัน",
|
||||||
"palette.search.placeholder.home": "ค้นหาคำสั่งและเซสชัน",
|
|
||||||
"palette.empty": "ไม่พบผลลัพธ์",
|
"palette.empty": "ไม่พบผลลัพธ์",
|
||||||
"palette.group.commands": "คำสั่ง",
|
"palette.group.commands": "คำสั่ง",
|
||||||
"palette.group.files": "ไฟล์",
|
"palette.group.files": "ไฟล์",
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ export const dict = {
|
|||||||
"command.session.unshare.description": "Bu oturumun paylaşımını durdur",
|
"command.session.unshare.description": "Bu oturumun paylaşımını durdur",
|
||||||
|
|
||||||
"palette.search.placeholder": "Dosya, komut ve oturum ara",
|
"palette.search.placeholder": "Dosya, komut ve oturum ara",
|
||||||
"palette.search.placeholder.home": "Komut ve oturum ara",
|
|
||||||
"palette.empty": "Sonuç bulunamadı",
|
"palette.empty": "Sonuç bulunamadı",
|
||||||
"palette.group.commands": "Komutlar",
|
"palette.group.commands": "Komutlar",
|
||||||
"palette.group.files": "Dosyalar",
|
"palette.group.files": "Dosyalar",
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ export const dict = {
|
|||||||
"command.session.unshare.description": "Припинити поширення цієї сесії",
|
"command.session.unshare.description": "Припинити поширення цієї сесії",
|
||||||
|
|
||||||
"palette.search.placeholder": "Пошук файлів, команд і сесій",
|
"palette.search.placeholder": "Пошук файлів, команд і сесій",
|
||||||
"palette.search.placeholder.home": "Пошук команд і сесій",
|
|
||||||
"palette.empty": "Результатів не знайдено",
|
"palette.empty": "Результатів не знайдено",
|
||||||
"palette.group.commands": "Команди",
|
"palette.group.commands": "Команди",
|
||||||
"palette.group.files": "Файли",
|
"palette.group.files": "Файли",
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ export const dict = {
|
|||||||
"command.session.unshare.description": "停止分享此会话",
|
"command.session.unshare.description": "停止分享此会话",
|
||||||
|
|
||||||
"palette.search.placeholder": "搜索文件、命令和会话",
|
"palette.search.placeholder": "搜索文件、命令和会话",
|
||||||
"palette.search.placeholder.home": "搜索命令和会话",
|
|
||||||
"palette.empty": "未找到结果",
|
"palette.empty": "未找到结果",
|
||||||
"palette.group.commands": "命令",
|
"palette.group.commands": "命令",
|
||||||
"palette.group.files": "文件",
|
"palette.group.files": "文件",
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ export const dict = {
|
|||||||
"command.session.unshare.description": "停止分享此工作階段",
|
"command.session.unshare.description": "停止分享此工作階段",
|
||||||
|
|
||||||
"palette.search.placeholder": "搜尋檔案、命令和工作階段",
|
"palette.search.placeholder": "搜尋檔案、命令和工作階段",
|
||||||
"palette.search.placeholder.home": "搜尋命令和工作階段",
|
|
||||||
"palette.empty": "找不到結果",
|
"palette.empty": "找不到結果",
|
||||||
"palette.group.commands": "命令",
|
"palette.group.commands": "命令",
|
||||||
"palette.group.files": "檔案",
|
"palette.group.files": "檔案",
|
||||||
|
|||||||
+13
-106
@@ -5,7 +5,6 @@ import {
|
|||||||
createMemo,
|
createMemo,
|
||||||
createResource,
|
createResource,
|
||||||
createRoot,
|
createRoot,
|
||||||
createSignal,
|
|
||||||
For,
|
For,
|
||||||
Match,
|
Match,
|
||||||
on,
|
on,
|
||||||
@@ -75,23 +74,6 @@ const HOME_SESSION_LIMIT = 64
|
|||||||
const HOME_SESSION_HEADER_STICKY_TOP = 12
|
const HOME_SESSION_HEADER_STICKY_TOP = 12
|
||||||
const HOME_SESSION_HEADER_TEXT_HEIGHT = 16
|
const HOME_SESSION_HEADER_TEXT_HEIGHT = 16
|
||||||
const HOME_SESSION_HEADER_FADE_DISTANCE = 16
|
const HOME_SESSION_HEADER_FADE_DISTANCE = 16
|
||||||
|
|
||||||
function containHomeWheel(event: WheelEvent, viewport: HTMLElement) {
|
|
||||||
if (event.defaultPrevented || event.ctrlKey || !event.deltaY) return
|
|
||||||
if (!(event.target instanceof Element)) return
|
|
||||||
|
|
||||||
const scrollable = event.target.closest<HTMLElement>("[data-scrollable]")
|
|
||||||
if (
|
|
||||||
scrollable !== viewport &&
|
|
||||||
scrollable &&
|
|
||||||
(event.deltaY < 0
|
|
||||||
? scrollable.scrollTop > 0
|
|
||||||
: scrollable.scrollTop < scrollable.scrollHeight - scrollable.clientHeight)
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
event.preventDefault()
|
|
||||||
}
|
|
||||||
const SHOW_HOME_SESSION_ARCHIVE = false
|
const SHOW_HOME_SESSION_ARCHIVE = false
|
||||||
const HOME_ROW_LAYOUT =
|
const HOME_ROW_LAYOUT =
|
||||||
"flex min-w-0 w-full shrink-0 cursor-default items-center rounded-[6px] bg-transparent text-left transition-[background-color,color,box-shadow] duration-[120ms] ease-in-out focus-visible:outline-none"
|
"flex min-w-0 w-full shrink-0 cursor-default items-center rounded-[6px] bg-transparent text-left transition-[background-color,color,box-shadow] duration-[120ms] ease-in-out focus-visible:outline-none"
|
||||||
@@ -162,7 +144,6 @@ function useHomeSessionHeaderOpacity(groups: () => HomeSessionGroup[]) {
|
|||||||
let content: HTMLDivElement | undefined
|
let content: HTMLDivElement | undefined
|
||||||
let positionFrame: number | undefined
|
let positionFrame: number | undefined
|
||||||
let resizeObserver: ResizeObserver | undefined
|
let resizeObserver: ResizeObserver | undefined
|
||||||
let stickyTop = HOME_SESSION_HEADER_STICKY_TOP
|
|
||||||
const headerRefs = new Map<HomeSessionGroup["id"], HTMLDivElement>()
|
const headerRefs = new Map<HomeSessionGroup["id"], HTMLDivElement>()
|
||||||
const headerOffsets = new Map<HomeSessionGroup["id"], number>()
|
const headerOffsets = new Map<HomeSessionGroup["id"], number>()
|
||||||
const [state, setState] = createStore({
|
const [state, setState] = createStore({
|
||||||
@@ -221,13 +202,6 @@ function useHomeSessionHeaderOpacity(groups: () => HomeSessionGroup[]) {
|
|||||||
|
|
||||||
function updatePositionCache() {
|
function updatePositionCache() {
|
||||||
if (!viewport) return
|
if (!viewport) return
|
||||||
const header = groups()
|
|
||||||
.map((group) => headerRefs.get(group.id))
|
|
||||||
.find((el) => el !== undefined)
|
|
||||||
if (header && typeof getComputedStyle === "function") {
|
|
||||||
const top = Number.parseFloat(getComputedStyle(header).top)
|
|
||||||
if (Number.isFinite(top)) stickyTop = top
|
|
||||||
}
|
|
||||||
groups().forEach((group) => {
|
groups().forEach((group) => {
|
||||||
const el = headerRefs.get(group.id)
|
const el = headerRefs.get(group.id)
|
||||||
if (!el) return
|
if (!el) return
|
||||||
@@ -243,7 +217,7 @@ function useHomeSessionHeaderOpacity(groups: () => HomeSessionGroup[]) {
|
|||||||
.slice(index + 1)
|
.slice(index + 1)
|
||||||
.map((item) => headerOffsets.get(item.id))
|
.map((item) => headerOffsets.get(item.id))
|
||||||
.find((offset) => offset !== undefined)
|
.find((offset) => offset !== undefined)
|
||||||
const fadeEnd = stickyTop + HOME_SESSION_HEADER_TEXT_HEIGHT
|
const fadeEnd = HOME_SESSION_HEADER_STICKY_TOP + HOME_SESSION_HEADER_TEXT_HEIGHT
|
||||||
const nextTop = nextOffset === undefined ? undefined : nextOffset - scrollTop
|
const nextTop = nextOffset === undefined ? undefined : nextOffset - scrollTop
|
||||||
const opacity =
|
const opacity =
|
||||||
nextTop === undefined ? 1 : Math.max(0, Math.min(1, (nextTop - fadeEnd) / HOME_SESSION_HEADER_FADE_DISTANCE))
|
nextTop === undefined ? 1 : Math.max(0, Math.min(1, (nextTop - fadeEnd) / HOME_SESSION_HEADER_FADE_DISTANCE))
|
||||||
@@ -297,9 +271,6 @@ export function NewHome() {
|
|||||||
const marked = useMarked()
|
const marked = useMarked()
|
||||||
const openSettings = useSettingsCommand()
|
const openSettings = useSettingsCommand()
|
||||||
let focusSessionSearch: (() => void) | undefined
|
let focusSessionSearch: (() => void) | undefined
|
||||||
let sessionViewport: HTMLDivElement | undefined
|
|
||||||
const [sessionThumbTrack, setSessionThumbTrack] = createSignal<HTMLDivElement>()
|
|
||||||
const [sessionHoverTarget, setSessionHoverTarget] = createSignal<HTMLElement>()
|
|
||||||
const [state, setState] = createStore({
|
const [state, setState] = createStore({
|
||||||
search: "",
|
search: "",
|
||||||
searchFocused: false,
|
searchFocused: false,
|
||||||
@@ -431,34 +402,6 @@ export function NewHome() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
command.register("home", () => [
|
command.register("home", () => [
|
||||||
{
|
|
||||||
id: "command.palette",
|
|
||||||
title: language.t("command.palette"),
|
|
||||||
hidden: true,
|
|
||||||
onSelect: async () => {
|
|
||||||
const conn = focusedServer()
|
|
||||||
if (!conn) return
|
|
||||||
const ctx = global.ensureServerCtx(conn)
|
|
||||||
const { DialogHomeCommandPaletteV2 } = await import("@/components/dialog-command-palette-v2")
|
|
||||||
void dialog.show(() => (
|
|
||||||
<DialogHomeCommandPaletteV2
|
|
||||||
server={conn}
|
|
||||||
onSelectSession={(entry) => {
|
|
||||||
if (!entry.sessionID || !entry.directory || !entry.server) return
|
|
||||||
const sessionID = entry.sessionID
|
|
||||||
const server = entry.server
|
|
||||||
const directory = entry.project?.worktree ?? entry.directory
|
|
||||||
ctx.projects.open(directory)
|
|
||||||
ctx.projects.touch(directory)
|
|
||||||
void startTransition(() => {
|
|
||||||
const tab = tabs.addSessionTab({ server, sessionId: sessionID })
|
|
||||||
tabs.select(tab)
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "home.sessions.search.focus",
|
id: "home.sessions.search.focus",
|
||||||
title: searchPlaceholder(),
|
title: searchPlaceholder(),
|
||||||
@@ -598,23 +541,8 @@ export function NewHome() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="rounded-[10px] shadow-[var(--v2-elevation-raised)] m-2 min-h-0 overflow-hidden bg-v2-background-bg-base self-stretch flex-1">
|
<div class="rounded-[10px] shadow-[var(--v2-elevation-raised)] m-2 min-h-0 lg:overflow-hidden bg-v2-background-bg-base self-stretch flex-1">
|
||||||
<ScrollView
|
<div class="mx-auto grid h-full w-full max-w-[1080px] grid-rows-[auto_minmax(0,1fr)_auto] gap-4 px-3 lg:grid-cols-[280px_minmax(0,720px)] lg:grid-rows-1 lg:gap-8 lg:px-6">
|
||||||
class="h-full [container-type:size]"
|
|
||||||
thumbContainer={sessionThumbTrack}
|
|
||||||
thumbHoverTarget={sessionHoverTarget}
|
|
||||||
viewportRef={(el) => {
|
|
||||||
sessionViewport = el
|
|
||||||
sessionHeaderOpacity.setViewport(el)
|
|
||||||
}}
|
|
||||||
onScroll={(event) => sessionHeaderOpacity.update(event.currentTarget.scrollTop)}
|
|
||||||
onWheel={(event) => {
|
|
||||||
if (!sessionViewport) return
|
|
||||||
if (event.target instanceof Node && sessionViewport.contains(event.target)) return
|
|
||||||
containHomeWheel(event, sessionViewport)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div class="mx-auto grid min-h-full w-full max-w-[1080px] grid-rows-[auto_minmax(0,1fr)_auto] gap-4 px-3 lg:grid-cols-[280px_minmax(0,720px)] lg:grid-rows-1 lg:gap-8 lg:px-6">
|
|
||||||
<HomeProjectColumn
|
<HomeProjectColumn
|
||||||
projects={projects()}
|
projects={projects()}
|
||||||
recentlyClosed={recentlyClosed()}
|
recentlyClosed={recentlyClosed()}
|
||||||
@@ -640,21 +568,11 @@ export function NewHome() {
|
|||||||
openSettings={openSettings}
|
openSettings={openSettings}
|
||||||
openHelp={() => platform.openLink("https://opencode.ai/desktop-feedback")}
|
openHelp={() => platform.openLink("https://opencode.ai/desktop-feedback")}
|
||||||
language={language}
|
language={language}
|
||||||
onWheel={(event) => {
|
|
||||||
if (sessionViewport) containHomeWheel(event, sessionViewport)
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<section
|
<section
|
||||||
ref={setSessionHoverTarget}
|
class="min-h-0 min-w-0 flex-1 flex flex-col pt-6 lg:pt-12 relative"
|
||||||
class="min-h-0 min-w-0 flex-1 flex flex-col"
|
|
||||||
aria-label={language.t("sidebar.project.recentSessions")}
|
aria-label={language.t("sidebar.project.recentSessions")}
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="sticky top-0 z-30 shrink-0 bg-v2-background-bg-base pb-3 pt-6 lg:pt-12"
|
|
||||||
onWheel={(event) => {
|
|
||||||
if (sessionViewport) containHomeWheel(event, sessionViewport)
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<HomeSessionSearch
|
<HomeSessionSearch
|
||||||
value={state.search}
|
value={state.search}
|
||||||
@@ -673,8 +591,13 @@ export function NewHome() {
|
|||||||
onClose={closeSearch}
|
onClose={closeSearch}
|
||||||
onSelect={selectSearchSession}
|
onSelect={selectSearchSession}
|
||||||
/>
|
/>
|
||||||
|
<ScrollView
|
||||||
|
class="mt-3 -mr-3 min-h-0 flex-1 relative"
|
||||||
|
viewportRef={sessionHeaderOpacity.setViewport}
|
||||||
|
onScroll={(event) => sessionHeaderOpacity.update(event.currentTarget.scrollTop)}
|
||||||
|
>
|
||||||
<Show when={groups().length > 0 && newSessionProject()}>
|
<Show when={groups().length > 0 && newSessionProject()}>
|
||||||
<div class="pointer-events-none absolute right-0 top-[84px] z-20 flex lg:top-[108px]">
|
<div class="pointer-events-none absolute top-3 right-3 z-20 flex">
|
||||||
<ButtonV2
|
<ButtonV2
|
||||||
data-action="home-new-session"
|
data-action="home-new-session"
|
||||||
variant="ghost-muted"
|
variant="ghost-muted"
|
||||||
@@ -687,16 +610,6 @@ export function NewHome() {
|
|||||||
</ButtonV2>
|
</ButtonV2>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
|
||||||
{/* Sticky chrome for the portaled session scrollbar — matches old sessions ScrollView bounds */}
|
|
||||||
<div class="pointer-events-none sticky top-[84px] z-40 h-0 -mr-3 lg:top-[108px]">
|
|
||||||
<div
|
|
||||||
ref={setSessionThumbTrack}
|
|
||||||
data-component="home-session-scroll-track"
|
|
||||||
class="relative ml-auto h-[calc(100cqh-84px)] w-3 lg:h-[calc(100cqh-108px)]"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="-mr-3 min-h-[calc(100cqh-72px)] lg:min-h-[calc(100cqh-96px)]">
|
|
||||||
<Show
|
<Show
|
||||||
when={!sessionLoad.isLoading}
|
when={!sessionLoad.isLoading}
|
||||||
fallback={
|
fallback={
|
||||||
@@ -740,7 +653,7 @@ export function NewHome() {
|
|||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</ScrollView>
|
||||||
</section>
|
</section>
|
||||||
<HomeUtilityNav
|
<HomeUtilityNav
|
||||||
class="flex lg:hidden"
|
class="flex lg:hidden"
|
||||||
@@ -749,7 +662,6 @@ export function NewHome() {
|
|||||||
language={language}
|
language={language}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ScrollView>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -771,7 +683,6 @@ function HomeProjectColumn(props: {
|
|||||||
openSettings: () => void
|
openSettings: () => void
|
||||||
openHelp: () => void
|
openHelp: () => void
|
||||||
language: ReturnType<typeof useLanguage>
|
language: ReturnType<typeof useLanguage>
|
||||||
onWheel: (event: WheelEvent) => void
|
|
||||||
}) {
|
}) {
|
||||||
const global = useGlobal()
|
const global = useGlobal()
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
@@ -788,12 +699,8 @@ function HomeProjectColumn(props: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<aside
|
<aside
|
||||||
class="mt-6 flex min-h-0 min-w-0 flex-col gap-4 overflow-hidden lg:sticky lg:top-14 lg:mt-14 lg:h-[calc(100cqh-56px)] lg:self-start lg:pt-[52px]"
|
class="mt-6 flex min-h-0 min-w-0 flex-col gap-4 overflow-hidden lg:mt-14 lg:pt-[52px]"
|
||||||
aria-label={props.language.t("home.projects")}
|
aria-label={props.language.t("home.projects")}
|
||||||
onWheel={(event) => {
|
|
||||||
if (event.target === event.currentTarget) return
|
|
||||||
props.onWheel(event)
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div class="flex h-7 min-w-0 shrink-0 items-center justify-between pl-1.5 pr-3">
|
<div class="flex h-7 min-w-0 shrink-0 items-center justify-between pl-1.5 pr-3">
|
||||||
<div class="text-v2-text-text-muted [font-weight:530]">{props.language.t("home.projects")}</div>
|
<div class="text-v2-text-text-muted [font-weight:530]">{props.language.t("home.projects")}</div>
|
||||||
@@ -1511,7 +1418,7 @@ function HomeSessionGroupHeader(props: {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={props.ref}
|
ref={props.ref}
|
||||||
class={`pointer-events-none sticky top-[84px] lg:top-[108px] flex h-7 min-w-0 items-center justify-between pl-3 bg-v2-background-bg-base ${props.elevated ? "home-session-group-header z-[5]" : "z-10"}`}
|
class={`pointer-events-none sticky top-3 flex h-7 min-w-0 items-center justify-between pl-3 bg-v2-background-bg-base ${props.elevated ? "home-session-group-header z-[5]" : "z-10"}`}
|
||||||
>
|
>
|
||||||
<div class={HOME_SECTION_LABEL} style={{ opacity: props.titleOpacity }}>
|
<div class={HOME_SECTION_LABEL} style={{ opacity: props.titleOpacity }}>
|
||||||
{props.title}
|
{props.title}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createEffect, Suspense, type ParentProps } from "solid-js"
|
import { createEffect, Suspense, type ParentProps } from "solid-js"
|
||||||
import { useNavigate } from "@solidjs/router"
|
import { useNavigate } from "@solidjs/router"
|
||||||
import { DebugBar } from "@/components/debug-bar"
|
import { DebugBar } from "@/components/debug-bar"
|
||||||
import { TabsInfoPopup } from "@/components/help-button"
|
import { HelpButton, TabsInfoPopup } from "@/components/help-button"
|
||||||
import { Titlebar, type TitlebarUpdate } from "@/components/titlebar"
|
import { Titlebar, type TitlebarUpdate } from "@/components/titlebar"
|
||||||
import { usePlatform } from "@/context/platform"
|
import { usePlatform } from "@/context/platform"
|
||||||
import { setNavigate } from "@/utils/notification-click"
|
import { setNavigate } from "@/utils/notification-click"
|
||||||
@@ -38,6 +38,7 @@ export default function NewLayout(props: ParentProps) {
|
|||||||
</main>
|
</main>
|
||||||
{import.meta.env.DEV && <DebugBar inline />}
|
{import.meta.env.DEV && <DebugBar inline />}
|
||||||
<TabsInfoPopup />
|
<TabsInfoPopup />
|
||||||
|
<HelpButton />
|
||||||
<ToastRegion v2 />
|
<ToastRegion v2 />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ import { useTheme, type ColorScheme } from "@opencode-ai/ui/theme/context"
|
|||||||
import { useCommand, type CommandOption } from "@/context/command"
|
import { useCommand, type CommandOption } from "@/context/command"
|
||||||
import { ConstrainDragXAxis, getDraggableId } from "@/utils/solid-dnd"
|
import { ConstrainDragXAxis, getDraggableId } from "@/utils/solid-dnd"
|
||||||
import { DebugBar } from "@/components/debug-bar"
|
import { DebugBar } from "@/components/debug-bar"
|
||||||
import { TabsInfoPopup } from "@/components/help-button"
|
import { HelpButton, TabsInfoPopup } from "@/components/help-button"
|
||||||
import { Titlebar, type TitlebarUpdate } from "@/components/titlebar"
|
import { Titlebar, type TitlebarUpdate } from "@/components/titlebar"
|
||||||
import { useDirectoryPicker } from "@/components/directory-picker"
|
import { useDirectoryPicker } from "@/components/directory-picker"
|
||||||
import { ServerConnection, useServer } from "@/context/server"
|
import { ServerConnection, useServer } from "@/context/server"
|
||||||
@@ -2396,6 +2396,7 @@ export default function LegacyLayout(props: ParentProps) {
|
|||||||
{import.meta.env.DEV && import.meta.env.VITE_DISABLE_DEBUG_BAR !== "1" && <DebugBar />}
|
{import.meta.env.DEV && import.meta.env.VITE_DISABLE_DEBUG_BAR !== "1" && <DebugBar />}
|
||||||
</div>
|
</div>
|
||||||
<TabsInfoPopup />
|
<TabsInfoPopup />
|
||||||
|
<HelpButton />
|
||||||
<ToastRegion v2={false} />
|
<ToastRegion v2={false} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { createStore } from "solid-js/store"
|
|||||||
import { Portal } from "solid-js/web"
|
import { Portal } from "solid-js/web"
|
||||||
import { useSearchParams } from "@solidjs/router"
|
import { useSearchParams } from "@solidjs/router"
|
||||||
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
||||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
|
||||||
import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon"
|
import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon"
|
||||||
import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2"
|
import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2"
|
||||||
import { NewSessionDesignView } from "@/components/session"
|
import { NewSessionDesignView } from "@/components/session"
|
||||||
@@ -52,7 +51,6 @@ export default function NewSessionPage() {
|
|||||||
const comments = useComments()
|
const comments = useComments()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const settings = useSettings()
|
const settings = useSettings()
|
||||||
const dialog = useDialog()
|
|
||||||
const command = useCommand()
|
const command = useCommand()
|
||||||
const providers = useProviders(() => sdk().directory)
|
const providers = useProviders(() => sdk().directory)
|
||||||
const openProviderSettings = useSettingsDialog("providers")
|
const openProviderSettings = useSettingsDialog("providers")
|
||||||
@@ -79,15 +77,6 @@ export default function NewSessionPage() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
command.register("new-session", () => [
|
command.register("new-session", () => [
|
||||||
{
|
|
||||||
id: "command.palette",
|
|
||||||
title: language.t("command.palette"),
|
|
||||||
hidden: true,
|
|
||||||
onSelect: async () => {
|
|
||||||
const { DialogSelectFile } = await import("@/components/dialog-select-file")
|
|
||||||
void dialog.show(() => <DialogSelectFile />)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "input.focus",
|
id: "input.focus",
|
||||||
title: language.t("command.input.focus"),
|
title: language.t("command.input.focus"),
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ import { useLocation, useNavigate, useParams, useSearchParams } from "@solidjs/r
|
|||||||
import { NewSessionView, SessionHeader } from "@/components/session"
|
import { NewSessionView, SessionHeader } from "@/components/session"
|
||||||
import { ErrorPage } from "@/pages/error"
|
import { ErrorPage } from "@/pages/error"
|
||||||
import { CommentsProvider, useComments } from "@/context/comments"
|
import { CommentsProvider, useComments } from "@/context/comments"
|
||||||
import { useCommand } from "@/context/command"
|
|
||||||
import { DirectoryDataProvider } from "@/pages/directory-layout"
|
import { DirectoryDataProvider } from "@/pages/directory-layout"
|
||||||
import { useServerSync } from "@/context/server-sync"
|
import { useServerSync } from "@/context/server-sync"
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
@@ -363,7 +362,6 @@ export default function Page() {
|
|||||||
const platform = usePlatform()
|
const platform = usePlatform()
|
||||||
const prompt = usePrompt()
|
const prompt = usePrompt()
|
||||||
const comments = useComments()
|
const comments = useComments()
|
||||||
const command = useCommand()
|
|
||||||
const terminal = useTerminal()
|
const terminal = useTerminal()
|
||||||
const [searchParams, setSearchParams] = useSearchParams<{ prompt?: string }>()
|
const [searchParams, setSearchParams] = useSearchParams<{ prompt?: string }>()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
@@ -1100,14 +1098,6 @@ export default function Page() {
|
|||||||
review: reviewTab,
|
review: reviewTab,
|
||||||
fileBrowser: () => newSessionDesign() && isDesktop() && !!params.id,
|
fileBrowser: () => newSessionDesign() && isDesktop() && !!params.id,
|
||||||
})
|
})
|
||||||
command.register("session-palette", () => [
|
|
||||||
{
|
|
||||||
id: "command.palette",
|
|
||||||
title: language.t("command.palette"),
|
|
||||||
hidden: true,
|
|
||||||
onSelect: () => command.trigger("file.open", "palette"),
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
const openReviewFile = createOpenReviewFile({
|
const openReviewFile = createOpenReviewFile({
|
||||||
showAllFiles,
|
showAllFiles,
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function createPromptInputController(input: {
|
|||||||
options: local.agent.list().map((agent) => agent.name),
|
options: local.agent.list().map((agent) => agent.name),
|
||||||
current: local.agent.current()?.name ?? "",
|
current: local.agent.current()?.name ?? "",
|
||||||
loading: agentsQuery.isLoading,
|
loading: agentsQuery.isLoading,
|
||||||
visible: local.agent.visible(),
|
visible: settings.visibility.customAgents(),
|
||||||
select: local.agent.set,
|
select: local.agent.set,
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useCommand, type CommandOption } from "@/context/command"
|
import { useCommand, type CommandOption } from "@/context/command"
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { useLocal, type ModelSelection } from "@/context/local"
|
import { useLocal, type ModelSelection } from "@/context/local"
|
||||||
|
import { useSettings } from "@/context/settings"
|
||||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||||
import { getCursorPosition, setCursorPosition } from "@/components/prompt-input/editor-dom"
|
import { getCursorPosition, setCursorPosition } from "@/components/prompt-input/editor-dom"
|
||||||
import { useSessionLayout } from "./session-layout"
|
import { useSessionLayout } from "./session-layout"
|
||||||
@@ -18,6 +19,7 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
|||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const local = useLocal()
|
const local = useLocal()
|
||||||
|
const settings = useSettings()
|
||||||
const { sessionKey } = useSessionLayout()
|
const { sessionKey } = useSessionLayout()
|
||||||
const sessionOwnership = createSessionOwnership(sessionKey)
|
const sessionOwnership = createSessionOwnership(sessionKey)
|
||||||
const model = input.model ?? local.model
|
const model = input.model ?? local.model
|
||||||
@@ -68,7 +70,7 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
|||||||
description: language.t("command.agent.cycle.description"),
|
description: language.t("command.agent.cycle.description"),
|
||||||
keybind: "mod+.",
|
keybind: "mod+.",
|
||||||
slash: "agent",
|
slash: "agent",
|
||||||
disabled: !local.agent.visible(),
|
disabled: !settings.visibility.customAgents(),
|
||||||
onSelect: () => local.agent.move(1),
|
onSelect: () => local.agent.move(1),
|
||||||
}),
|
}),
|
||||||
agentCommand({
|
agentCommand({
|
||||||
@@ -76,7 +78,7 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
|||||||
title: language.t("command.agent.cycle.reverse"),
|
title: language.t("command.agent.cycle.reverse"),
|
||||||
description: language.t("command.agent.cycle.reverse.description"),
|
description: language.t("command.agent.cycle.reverse.description"),
|
||||||
keybind: "shift+mod+.",
|
keybind: "shift+mod+.",
|
||||||
disabled: !local.agent.visible(),
|
disabled: !settings.visibility.customAgents(),
|
||||||
onSelect: () => local.agent.move(-1),
|
onSelect: () => local.agent.move(-1),
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -468,7 +468,7 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
|||||||
id: "file.open",
|
id: "file.open",
|
||||||
title: language.t("command.file.open"),
|
title: language.t("command.file.open"),
|
||||||
description: language.t("palette.search.placeholder"),
|
description: language.t("palette.search.placeholder"),
|
||||||
keybind: "mod+p",
|
keybind: "mod+k,mod+p",
|
||||||
slash: "open",
|
slash: "open",
|
||||||
onSelect: openFile,
|
onSelect: openFile,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
|
||||||
import type { GlobalSession, Project } from "@opencode-ai/sdk/v2/client"
|
|
||||||
import { createRoot } from "solid-js"
|
|
||||||
import { createServerSessionEntries } from "@/components/command-palette"
|
|
||||||
import type { LocalProject } from "@/context/layout"
|
|
||||||
import { ServerConnection } from "@/context/server"
|
|
||||||
import { getProjectAvatarSource } from "@/pages/layout/helpers"
|
|
||||||
|
|
||||||
const stored: Project = {
|
|
||||||
id: "project-1",
|
|
||||||
name: "Palette project",
|
|
||||||
worktree: "/workspace/project",
|
|
||||||
sandboxes: [],
|
|
||||||
time: { created: 1, updated: 1 },
|
|
||||||
}
|
|
||||||
|
|
||||||
const session: GlobalSession = {
|
|
||||||
id: "session-1",
|
|
||||||
slug: "session-1",
|
|
||||||
projectID: stored.id,
|
|
||||||
directory: stored.worktree,
|
|
||||||
title: "Palette session",
|
|
||||||
version: "1",
|
|
||||||
time: { created: 1, updated: 2 },
|
|
||||||
project: { id: stored.id, name: stored.name, worktree: stored.worktree },
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("command palette sessions", () => {
|
|
||||||
test("uses the home project avatar and cancels superseded searches", async () => {
|
|
||||||
const server = ServerConnection.Key.make("selected-server")
|
|
||||||
const opened: LocalProject = {
|
|
||||||
...stored,
|
|
||||||
icon: { override: "home-project-avatar" },
|
|
||||||
expanded: true,
|
|
||||||
}
|
|
||||||
const searches: string[] = []
|
|
||||||
const result = await new Promise<Awaited<ReturnType<ReturnType<typeof createServerSessionEntries>>>>(
|
|
||||||
(resolve, reject) => {
|
|
||||||
createRoot((dispose) => {
|
|
||||||
const search = createServerSessionEntries({
|
|
||||||
server,
|
|
||||||
opened: () => [opened],
|
|
||||||
stored: () => [{ ...stored, icon: { url: "stored-project-avatar" } }],
|
|
||||||
load: async (text) => {
|
|
||||||
searches.push(text)
|
|
||||||
return {
|
|
||||||
data: [session, { ...session, id: "archived-session", time: { ...session.time, archived: 3 } }],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
untitled: () => "Untitled",
|
|
||||||
category: () => "Sessions",
|
|
||||||
})
|
|
||||||
const first = search("palette")
|
|
||||||
const second = search("palette session")
|
|
||||||
Promise.all([first, second])
|
|
||||||
.then(([cancelled, entries]) => {
|
|
||||||
expect(cancelled).toEqual([])
|
|
||||||
resolve(entries)
|
|
||||||
})
|
|
||||||
.catch(reject)
|
|
||||||
.finally(dispose)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(searches).toEqual(["palette session"])
|
|
||||||
expect(result).toHaveLength(1)
|
|
||||||
expect(getProjectAvatarSource(result[0]?.project?.id, result[0]?.project?.icon)).toBe("home-project-avatar")
|
|
||||||
expect(result[0]).toMatchObject({
|
|
||||||
server,
|
|
||||||
sessionID: session.id,
|
|
||||||
description: stored.name,
|
|
||||||
project: { id: stored.id, icon: opened.icon },
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -31,13 +31,11 @@ function run(target) {
|
|||||||
|
|
||||||
const envPath = process.env.OPENCODE_BIN_PATH
|
const envPath = process.env.OPENCODE_BIN_PATH
|
||||||
const scriptDir = path.dirname(fs.realpathSync(__filename))
|
const scriptDir = path.dirname(fs.realpathSync(__filename))
|
||||||
const command = path.basename(__filename).replace(/\.cjs$/, "")
|
const cached = path.join(scriptDir, ".opencode2")
|
||||||
const nodeBuild = command === "opencode2-node"
|
|
||||||
const cached = path.join(scriptDir, `.${command}`)
|
|
||||||
const platform = { darwin: "darwin", linux: "linux", win32: "windows" }[os.platform()] || os.platform()
|
const platform = { darwin: "darwin", linux: "linux", win32: "windows" }[os.platform()] || os.platform()
|
||||||
const arch = { x64: "x64", arm64: "arm64", arm: "arm" }[os.arch()] || os.arch()
|
const arch = { x64: "x64", arm64: "arm64", arm: "arm" }[os.arch()] || os.arch()
|
||||||
const base = `@opencode-ai/cli${nodeBuild ? "-node" : ""}-` + platform + "-" + arch
|
const base = "@opencode-ai/cli-" + platform + "-" + arch
|
||||||
const binary = platform === "windows" ? `${command}.exe` : command
|
const binary = platform === "windows" ? "opencode2.exe" : "opencode2"
|
||||||
|
|
||||||
function supportsAvx2() {
|
function supportsAvx2() {
|
||||||
if (arch !== "x64") return false
|
if (arch !== "x64") return false
|
||||||
@@ -79,7 +77,6 @@ function supportsAvx2() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const names = (() => {
|
const names = (() => {
|
||||||
if (nodeBuild) return [base]
|
|
||||||
const baseline = arch === "x64" && !supportsAvx2()
|
const baseline = arch === "x64" && !supportsAvx2()
|
||||||
if (platform === "linux") {
|
if (platform === "linux") {
|
||||||
const musl = (() => {
|
const musl = (() => {
|
||||||
@@ -124,7 +121,7 @@ function findBinary(startDir) {
|
|||||||
const resolved = envPath || (fs.existsSync(cached) ? cached : findBinary(scriptDir))
|
const resolved = envPath || (fs.existsSync(cached) ? cached : findBinary(scriptDir))
|
||||||
if (!resolved) {
|
if (!resolved) {
|
||||||
console.error(
|
console.error(
|
||||||
`It seems that your package manager failed to install the right ${command} CLI package. Try manually installing ` +
|
"It seems that your package manager failed to install the right opencode2 CLI package. Try manually installing " +
|
||||||
names.map((name) => `"${name}"`).join(" or ") +
|
names.map((name) => `"${name}"`).join(" or ") +
|
||||||
" package",
|
" package",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@opencode-ai/cli",
|
"name": "@opencode-ai/cli",
|
||||||
"version": "1.18.3",
|
"version": "1.17.18",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -26,7 +26,6 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "bun run script/build.ts",
|
"build": "bun run script/build.ts",
|
||||||
"build:node": "bun run script/build-node.ts",
|
|
||||||
"dev": "bun run src/index.ts",
|
"dev": "bun run src/index.ts",
|
||||||
"test": "bun test --timeout 30000 --only-failures",
|
"test": "bun test --timeout 30000 --only-failures",
|
||||||
"typecheck": "tsgo --noEmit"
|
"typecheck": "tsgo --noEmit"
|
||||||
@@ -52,8 +51,7 @@
|
|||||||
"semver": "catalog:",
|
"semver": "catalog:",
|
||||||
"solid-js": "catalog:",
|
"solid-js": "catalog:",
|
||||||
"strip-ansi": "7.1.2",
|
"strip-ansi": "7.1.2",
|
||||||
"uqr": "0.1.3",
|
"uqr": "0.1.3"
|
||||||
"ws": "8.21.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@opencode-ai/script": "workspace:*",
|
"@opencode-ai/script": "workspace:*",
|
||||||
@@ -61,19 +59,6 @@
|
|||||||
"@tsconfig/bun": "catalog:",
|
"@tsconfig/bun": "catalog:",
|
||||||
"@types/bun": "catalog:",
|
"@types/bun": "catalog:",
|
||||||
"@types/semver": "catalog:",
|
"@types/semver": "catalog:",
|
||||||
"@typescript/native-preview": "catalog:",
|
"@typescript/native-preview": "catalog:"
|
||||||
"@lydell/node-pty-darwin-arm64": "1.2.0-beta.12",
|
|
||||||
"@lydell/node-pty-darwin-x64": "1.2.0-beta.12",
|
|
||||||
"@lydell/node-pty-linux-arm64": "1.2.0-beta.12",
|
|
||||||
"@lydell/node-pty-linux-x64": "1.2.0-beta.12",
|
|
||||||
"@lydell/node-pty-win32-arm64": "1.2.0-beta.12",
|
|
||||||
"@lydell/node-pty-win32-x64": "1.2.0-beta.12",
|
|
||||||
"@parcel/watcher-darwin-arm64": "2.5.1",
|
|
||||||
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
|
|
||||||
"@parcel/watcher-linux-x64-glibc": "2.5.1",
|
|
||||||
"@parcel/watcher-win32-arm64": "2.5.1",
|
|
||||||
"@parcel/watcher-win32-x64": "2.5.1",
|
|
||||||
"vite": "catalog:",
|
|
||||||
"vite-plugin-solid": "catalog:"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,203 +0,0 @@
|
|||||||
#!/usr/bin/env bun
|
|
||||||
|
|
||||||
import { spawnSync } from "node:child_process"
|
|
||||||
import { createHash } from "node:crypto"
|
|
||||||
import { chmod, copyFile, mkdir, mkdtemp, realpath, rename, rm, stat, writeFile } from "node:fs/promises"
|
|
||||||
import os from "node:os"
|
|
||||||
import path from "node:path"
|
|
||||||
import { build } from "vite"
|
|
||||||
import { Script } from "@opencode-ai/script"
|
|
||||||
import pkg from "../package.json"
|
|
||||||
import { modelsData } from "./generate"
|
|
||||||
import { collectNodeAssets, copyNodeAssets, hashNodeAssets, seaAssetMap } from "./node-assets"
|
|
||||||
import { mainConfig } from "../vite.node.config"
|
|
||||||
import { nodeExecArgv, nodeTarget, type NodeTarget } from "../src/node/target"
|
|
||||||
|
|
||||||
const NODE_VERSION = "26.4.0"
|
|
||||||
const dir = path.resolve(import.meta.dirname, "..")
|
|
||||||
const outdir = path.resolve(
|
|
||||||
dir,
|
|
||||||
process.argv.find((arg) => arg.startsWith("--outdir="))?.slice("--outdir=".length) ?? "dist",
|
|
||||||
)
|
|
||||||
if (outdir === dir) throw new Error("--outdir must not be the package directory")
|
|
||||||
if (outdir === path.join(dir, "dist-node")) {
|
|
||||||
throw new Error("--outdir must not be dist-node because it contains temporary files")
|
|
||||||
}
|
|
||||||
const bundleOnly = process.argv.includes("--bundle-only")
|
|
||||||
const single = process.argv.includes("--single")
|
|
||||||
const skipInstall = process.argv.includes("--skip-install")
|
|
||||||
const requested = process.argv.find((arg) => arg.startsWith("--target="))?.slice("--target=".length)
|
|
||||||
const allTargets = [
|
|
||||||
nodeTarget("linux", "arm64"),
|
|
||||||
nodeTarget("linux", "x64"),
|
|
||||||
nodeTarget("darwin", "arm64"),
|
|
||||||
nodeTarget("win32", "arm64"),
|
|
||||||
nodeTarget("win32", "x64"),
|
|
||||||
]
|
|
||||||
const targets = requested
|
|
||||||
? allTargets.filter((target) => targetName(target) === requested)
|
|
||||||
: single || bundleOnly
|
|
||||||
? [nodeTarget(process.platform, process.arch)]
|
|
||||||
: allTargets
|
|
||||||
|
|
||||||
if (targets.length === 0) {
|
|
||||||
if (requested === "darwin-x64") throw new Error("Node 26.4 SEA does not support macOS x64")
|
|
||||||
throw new Error(`Unknown Node target: ${requested}`)
|
|
||||||
}
|
|
||||||
if (!bundleOnly && targets.some((target) => target.platform === "darwin" && target.arch === "x64")) {
|
|
||||||
throw new Error("Node 26.4 SEA does not support macOS x64")
|
|
||||||
}
|
|
||||||
|
|
||||||
process.chdir(dir)
|
|
||||||
if (!skipInstall) run(process.execPath, ["install", "--os=*", "--cpu=*"])
|
|
||||||
if (!bundleOnly) await rm(outdir, { recursive: true, force: true })
|
|
||||||
const builder =
|
|
||||||
!bundleOnly || targets.some((target) => target.platform === process.platform && target.arch === process.arch)
|
|
||||||
? await resolveHostNode()
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
for (const target of targets) {
|
|
||||||
console.log(`building cli-node-${targetName(target)}`)
|
|
||||||
const assets = await collectNodeAssets(target)
|
|
||||||
await rm("dist-node", { recursive: true, force: true })
|
|
||||||
const assetHash = await hashNodeAssets(assets)
|
|
||||||
const input = { version: Script.version, channel: Script.channel, models: modelsData, assetHash, target }
|
|
||||||
await build(mainConfig(input))
|
|
||||||
await copyNodeAssets(assets)
|
|
||||||
|
|
||||||
const host = target.platform === process.platform && target.arch === process.arch
|
|
||||||
if (host) {
|
|
||||||
if (!builder) throw new Error("Node SEA builder is unavailable")
|
|
||||||
run(builder, [...nodeExecArgv, "dist-node/opencode.mjs", "--version"])
|
|
||||||
run(builder, [...nodeExecArgv, "dist-node/opencode.mjs", "--help"])
|
|
||||||
}
|
|
||||||
if (bundleOnly) continue
|
|
||||||
|
|
||||||
const name = `cli-node-${targetName(target)}`
|
|
||||||
const binary = target.platform === "win32" ? "opencode2-node.exe" : "opencode2-node"
|
|
||||||
const output = path.join(outdir, name, "bin", binary)
|
|
||||||
if (!builder) throw new Error("Node SEA builder is unavailable")
|
|
||||||
await mkdir(path.dirname(output), { recursive: true })
|
|
||||||
const config = {
|
|
||||||
main: "dist-node/opencode.mjs",
|
|
||||||
mainFormat: "module",
|
|
||||||
executable: await resolveTargetNode(target, builder),
|
|
||||||
output: path.relative(dir, output),
|
|
||||||
disableExperimentalSEAWarning: true,
|
|
||||||
useSnapshot: false,
|
|
||||||
useCodeCache: false,
|
|
||||||
execArgv: nodeExecArgv,
|
|
||||||
execArgvExtension: "none",
|
|
||||||
assets: await seaAssetMap(),
|
|
||||||
}
|
|
||||||
await writeFile("dist-node/sea.json", `${JSON.stringify(config, null, 2)}\n`)
|
|
||||||
run(builder, ["--build-sea", "dist-node/sea.json"])
|
|
||||||
if (target.platform !== "win32") await chmod(output, 0o755)
|
|
||||||
if (target.platform === "darwin" && process.platform === "darwin") run("codesign", ["--sign", "-", output])
|
|
||||||
if (target.platform === "darwin" && process.platform !== "darwin") {
|
|
||||||
console.warn(`${output} must be signed on macOS before it can run`)
|
|
||||||
}
|
|
||||||
await writeFile(
|
|
||||||
path.join(outdir, name, "package.json"),
|
|
||||||
`${JSON.stringify(
|
|
||||||
{
|
|
||||||
name: `@opencode-ai/${name}`,
|
|
||||||
version: Script.version,
|
|
||||||
license: pkg.license,
|
|
||||||
repository: { type: "git", url: "git+https://github.com/anomalyco/opencode.git" },
|
|
||||||
os: [target.platform],
|
|
||||||
cpu: [target.arch],
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
2,
|
|
||||||
)}\n`,
|
|
||||||
)
|
|
||||||
if (host) await smoke(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resolveHostNode() {
|
|
||||||
const candidates = [process.env.NODE_BIN, "node"].filter((item): item is string => Boolean(item))
|
|
||||||
for (const candidate of candidates) {
|
|
||||||
const result = spawnSync(
|
|
||||||
candidate,
|
|
||||||
["-p", "JSON.stringify({version:process.versions.node,path:process.execPath})"],
|
|
||||||
{
|
|
||||||
encoding: "utf8",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if (result.status !== 0) continue
|
|
||||||
const info = JSON.parse(result.stdout) as { version: string; path: string }
|
|
||||||
if (info.version === NODE_VERSION) return realpath(info.path)
|
|
||||||
}
|
|
||||||
return resolveTargetNode(nodeTarget(process.platform, process.arch))
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resolveTargetNode(target: NodeTarget, host?: string) {
|
|
||||||
if (host && target.platform === process.platform && target.arch === process.arch) return host
|
|
||||||
const cache = path.resolve(dir, ".cache", "node")
|
|
||||||
const platform = target.platform === "win32" ? "win" : target.platform
|
|
||||||
const archiveName = `node-v${NODE_VERSION}-${platform}-${target.arch}`
|
|
||||||
const targetDirectory = path.join(cache, archiveName)
|
|
||||||
const executable = path.join(targetDirectory, target.platform === "win32" ? "node.exe" : "bin/node")
|
|
||||||
if (
|
|
||||||
(await stat(executable).then(
|
|
||||||
() => true,
|
|
||||||
() => false,
|
|
||||||
)) &&
|
|
||||||
(await stat(path.join(targetDirectory, ".verified")).then(
|
|
||||||
() => true,
|
|
||||||
() => false,
|
|
||||||
))
|
|
||||||
)
|
|
||||||
return realpath(executable)
|
|
||||||
await mkdir(cache, { recursive: true })
|
|
||||||
const extension = target.platform === "win32" ? "zip" : "tar.gz"
|
|
||||||
const filename = `${archiveName}.${extension}`
|
|
||||||
const archive = path.join(cache, filename)
|
|
||||||
const base = `https://nodejs.org/dist/v${NODE_VERSION}`
|
|
||||||
const [response, sums] = await Promise.all([fetch(`${base}/${filename}`), fetch(`${base}/SHASUMS256.txt`)])
|
|
||||||
if (!response.ok) throw new Error(`Failed to download Node ${NODE_VERSION}: ${response.status}`)
|
|
||||||
if (!sums.ok) throw new Error(`Failed to download Node ${NODE_VERSION} checksums: ${sums.status}`)
|
|
||||||
const data = new Uint8Array(await response.arrayBuffer())
|
|
||||||
const expected = (await sums.text())
|
|
||||||
.split("\n")
|
|
||||||
.find((line) => line.endsWith(` ${filename}`))
|
|
||||||
?.split(/\s+/)[0]
|
|
||||||
if (!expected) throw new Error(`Missing checksum for ${filename}`)
|
|
||||||
if (createHash("sha256").update(data).digest("hex") !== expected) throw new Error(`Checksum mismatch for ${filename}`)
|
|
||||||
await writeFile(archive, data)
|
|
||||||
const temporary = path.join(cache, `${archiveName}.${process.pid}.tmp`)
|
|
||||||
await rm(temporary, { recursive: true, force: true })
|
|
||||||
await mkdir(temporary)
|
|
||||||
if (target.platform !== "win32") run("tar", ["-xzf", archive, "-C", temporary])
|
|
||||||
if (target.platform === "win32" && process.platform === "win32") {
|
|
||||||
run(path.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe"), ["-xf", archive, "-C", temporary])
|
|
||||||
}
|
|
||||||
if (target.platform === "win32" && process.platform !== "win32") run("unzip", ["-q", archive, "-d", temporary])
|
|
||||||
await rm(targetDirectory, { recursive: true, force: true })
|
|
||||||
await rename(path.join(temporary, archiveName), targetDirectory)
|
|
||||||
await writeFile(path.join(targetDirectory, ".verified"), `${expected}\n`)
|
|
||||||
await rm(temporary, { recursive: true, force: true })
|
|
||||||
await rm(archive, { force: true })
|
|
||||||
return realpath(executable)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function smoke(output: string) {
|
|
||||||
const root = await mkdtemp(path.join(os.tmpdir(), "opencode-node-smoke-"))
|
|
||||||
const executable = path.join(root, path.basename(output))
|
|
||||||
await copyFile(output, executable)
|
|
||||||
if (process.platform !== "win32") await chmod(executable, 0o755)
|
|
||||||
run(executable, ["--version"], root)
|
|
||||||
run(executable, ["--help"], root)
|
|
||||||
await rm(root, { recursive: true, force: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
function targetName(target: NodeTarget) {
|
|
||||||
return `${target.platform === "win32" ? "windows" : target.platform}-${target.arch}`
|
|
||||||
}
|
|
||||||
|
|
||||||
function run(command: string, args: readonly string[], cwd = dir) {
|
|
||||||
const result = spawnSync(command, args, { cwd, stdio: "inherit", env: process.env })
|
|
||||||
if (result.error) throw result.error
|
|
||||||
if (result.status !== 0) throw new Error(`${command} exited with status ${result.status ?? "unknown"}`)
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env bun
|
#!/usr/bin/env bun
|
||||||
|
|
||||||
import { $ } from "bun"
|
import { $ } from "bun"
|
||||||
|
import fs from "fs"
|
||||||
import { rm } from "fs/promises"
|
import { rm } from "fs/promises"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Script } from "@opencode-ai/script"
|
import { Script } from "@opencode-ai/script"
|
||||||
@@ -10,14 +11,9 @@ import { modelsData } from "./generate"
|
|||||||
|
|
||||||
const dir = path.resolve(import.meta.dirname, "..")
|
const dir = path.resolve(import.meta.dirname, "..")
|
||||||
const binary = "opencode2"
|
const binary = "opencode2"
|
||||||
const outdir = path.resolve(
|
|
||||||
dir,
|
|
||||||
process.argv.find((arg) => arg.startsWith("--outdir="))?.slice("--outdir=".length) ?? "dist",
|
|
||||||
)
|
|
||||||
if (outdir === dir) throw new Error("--outdir must not be the package directory")
|
|
||||||
process.chdir(dir)
|
process.chdir(dir)
|
||||||
|
|
||||||
await rm(outdir, { recursive: true, force: true })
|
await rm("dist", { recursive: true, force: true })
|
||||||
|
|
||||||
const singleFlag = process.argv.includes("--single")
|
const singleFlag = process.argv.includes("--single")
|
||||||
const baselineFlag = process.argv.includes("--baseline")
|
const baselineFlag = process.argv.includes("--baseline")
|
||||||
@@ -54,6 +50,10 @@ const targets = singleFlag
|
|||||||
|
|
||||||
if (!skipInstall) await $`bun install --os="*" --cpu="*" @opentui/core@${pkg.dependencies["@opentui/core"]}`
|
if (!skipInstall) await $`bun install --os="*" --cpu="*" @opentui/core@${pkg.dependencies["@opentui/core"]}`
|
||||||
|
|
||||||
|
const localParserWorker = path.resolve(dir, "node_modules/@opentui/core/parser.worker.js")
|
||||||
|
const rootParserWorker = path.resolve(dir, "../../node_modules/@opentui/core/parser.worker.js")
|
||||||
|
const parserWorker = fs.realpathSync(fs.existsSync(localParserWorker) ? localParserWorker : rootParserWorker)
|
||||||
|
|
||||||
for (const item of targets) {
|
for (const item of targets) {
|
||||||
const target = [
|
const target = [
|
||||||
binary,
|
binary,
|
||||||
@@ -67,7 +67,7 @@ for (const item of targets) {
|
|||||||
const name = target.replace(binary, "cli")
|
const name = target.replace(binary, "cli")
|
||||||
console.log(`building ${name}`)
|
console.log(`building ${name}`)
|
||||||
const result = await Bun.build({
|
const result = await Bun.build({
|
||||||
entrypoints: ["./src/index.ts"],
|
entrypoints: ["./src/index.ts", parserWorker],
|
||||||
tsconfig: "./tsconfig.json",
|
tsconfig: "./tsconfig.json",
|
||||||
plugins: [plugin],
|
plugins: [plugin],
|
||||||
external: ["node-gyp"],
|
external: ["node-gyp"],
|
||||||
@@ -81,7 +81,7 @@ for (const item of targets) {
|
|||||||
autoloadTsconfig: true,
|
autoloadTsconfig: true,
|
||||||
autoloadPackageJson: true,
|
autoloadPackageJson: true,
|
||||||
target: target.replace(binary, "bun") as Bun.Build.CompileTarget,
|
target: target.replace(binary, "bun") as Bun.Build.CompileTarget,
|
||||||
outfile: path.join(outdir, name, "bin", binary),
|
outfile: `./dist/${name}/bin/${binary}`,
|
||||||
execArgv: [`--user-agent=${binary}/${Script.version}`, "--use-system-ca", "--"],
|
execArgv: [`--user-agent=${binary}/${Script.version}`, "--use-system-ca", "--"],
|
||||||
windows: {},
|
windows: {},
|
||||||
},
|
},
|
||||||
@@ -93,6 +93,10 @@ for (const item of targets) {
|
|||||||
OPENCODE_LIBC: item.os === "linux" ? `'${item.abi ?? "glibc"}'` : "undefined",
|
OPENCODE_LIBC: item.os === "linux" ? `'${item.abi ?? "glibc"}'` : "undefined",
|
||||||
// FFF_LIBC selects the fff native lib variant: "musl" or "gnu".
|
// FFF_LIBC selects the fff native lib variant: "musl" or "gnu".
|
||||||
FFF_LIBC: item.os === "linux" ? `'${item.abi ?? "gnu"}'` : "undefined",
|
FFF_LIBC: item.os === "linux" ? `'${item.abi ?? "gnu"}'` : "undefined",
|
||||||
|
OTUI_TREE_SITTER_WORKER_PATH:
|
||||||
|
(item.os === "win32" ? '"B:/~BUN/root/' : '"/$bunfs/root/') +
|
||||||
|
path.relative(dir, parserWorker).replaceAll("\\", "/") +
|
||||||
|
'"',
|
||||||
...(item.os === "linux" ? { "process.env.OPENTUI_LIBC": JSON.stringify(item.abi ?? "glibc") } : {}),
|
...(item.os === "linux" ? { "process.env.OPENTUI_LIBC": JSON.stringify(item.abi ?? "glibc") } : {}),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -103,7 +107,7 @@ for (const item of targets) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await Bun.write(
|
await Bun.write(
|
||||||
path.join(outdir, name, "package.json"),
|
`./dist/${name}/package.json`,
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
{
|
{
|
||||||
name: `@opencode-ai/${name}`,
|
name: `@opencode-ai/${name}`,
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import { readFile } from "node:fs/promises"
|
|
||||||
|
|
||||||
const modelsUrl = process.env.OPENCODE_MODELS_URL || "https://models.dev"
|
const modelsUrl = process.env.OPENCODE_MODELS_URL || "https://models.dev"
|
||||||
|
|
||||||
export const modelsData = process.env.MODELS_DEV_API_JSON
|
export const modelsData = process.env.MODELS_DEV_API_JSON
|
||||||
? await readFile(process.env.MODELS_DEV_API_JSON, "utf8")
|
? await Bun.file(process.env.MODELS_DEV_API_JSON).text()
|
||||||
: await fetch(`${modelsUrl}/api.json`).then((response) => response.text())
|
: await fetch(`${modelsUrl}/api.json`).then((response) => response.text())
|
||||||
|
|
||||||
console.log("Loaded models.dev snapshot")
|
console.log("Loaded models.dev snapshot")
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
import { createHash } from "node:crypto"
|
|
||||||
import { copyFile, mkdir, readdir, readFile, stat } from "node:fs/promises"
|
|
||||||
import { createRequire } from "node:module"
|
|
||||||
import path from "node:path"
|
|
||||||
import { fileURLToPath } from "node:url"
|
|
||||||
import { getNodeAssets } from "@opentui/core/node-assets"
|
|
||||||
import { attentionSoundAssets, type NodeTarget, photonWasmAsset } from "../src/node/target"
|
|
||||||
|
|
||||||
const dir = path.resolve(import.meta.dirname, "..")
|
|
||||||
|
|
||||||
// Bun's compiler discovers file imports and embeds them in its virtual filesystem. Vite only bundles the JavaScript
|
|
||||||
// portion of the Node executable, while SEA embeds only the assets explicitly listed in its build configuration.
|
|
||||||
// Collect and stage those files under stable keys so the SEA prelude can extract them to real paths at startup;
|
|
||||||
// native addons, helper executables, and other path-based consumers cannot use assets directly from SEA memory.
|
|
||||||
export type NodeAsset = {
|
|
||||||
readonly key: string
|
|
||||||
readonly source: string
|
|
||||||
}
|
|
||||||
|
|
||||||
async function files(root: string, current = root): Promise<string[]> {
|
|
||||||
return (
|
|
||||||
await Promise.all(
|
|
||||||
(await readdir(current, { withFileTypes: true })).map((entry) => {
|
|
||||||
const target = path.join(current, entry.name)
|
|
||||||
return entry.isDirectory() ? files(root, target) : [path.relative(root, target)]
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
).flat()
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function collectNodeAssets(target: NodeTarget) {
|
|
||||||
const ptyEntry = fileURLToPath(import.meta.resolve(target.nodePtyPackage))
|
|
||||||
const ptyRoot = path.resolve(path.dirname(ptyEntry), "..")
|
|
||||||
const assets: NodeAsset[] = [
|
|
||||||
...getNodeAssets({
|
|
||||||
platform: target.platform,
|
|
||||||
arch: target.arch,
|
|
||||||
...(target.platform === "linux" ? { libc: "glibc" as const } : {}),
|
|
||||||
}),
|
|
||||||
{ key: target.parcelWatcherAsset, source: fileURLToPath(import.meta.resolve(target.parcelWatcherPackage)) },
|
|
||||||
{
|
|
||||||
key: photonWasmAsset,
|
|
||||||
source: createRequire(path.resolve(dir, "../core/package.json")).resolve(photonWasmAsset),
|
|
||||||
},
|
|
||||||
...attentionSoundAssets.map((key) => ({
|
|
||||||
key,
|
|
||||||
source: path.resolve(dir, "../ui/src/assets/audio", path.basename(key)),
|
|
||||||
})),
|
|
||||||
...(await files(ptyRoot))
|
|
||||||
.filter((relative) => !relative.endsWith(".map") && !relative.endsWith(".pdb"))
|
|
||||||
.map((relative) => ({
|
|
||||||
key: `${target.nodePtyPackage}/${relative}`,
|
|
||||||
source: path.join(ptyRoot, relative),
|
|
||||||
})),
|
|
||||||
]
|
|
||||||
await Promise.all(assets.map((asset) => stat(asset.source)))
|
|
||||||
return assets
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function hashNodeAssets(assets: readonly NodeAsset[]) {
|
|
||||||
const hash = createHash("sha256")
|
|
||||||
for (const asset of assets.toSorted((left, right) => left.key.localeCompare(right.key))) {
|
|
||||||
hash.update(asset.key)
|
|
||||||
hash.update(await readFile(asset.source))
|
|
||||||
}
|
|
||||||
return hash.digest("hex").slice(0, 16)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function copyNodeAssets(assets: readonly NodeAsset[]) {
|
|
||||||
const root = path.join(dir, "dist-node", "assets")
|
|
||||||
await Promise.all(
|
|
||||||
assets.map(async (asset) => {
|
|
||||||
const target = path.join(root, asset.key)
|
|
||||||
await mkdir(path.dirname(target), { recursive: true })
|
|
||||||
await copyFile(asset.source, target)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function seaAssetMap() {
|
|
||||||
const root = path.join(dir, "dist-node", "assets")
|
|
||||||
return Object.fromEntries((await files(root)).map((key) => [key.replaceAll(path.sep, "/"), path.join(root, key)]))
|
|
||||||
}
|
|
||||||
@@ -18,26 +18,22 @@ async function publish(dir: string, name: string, version: string) {
|
|||||||
await $`npm publish *.tgz --access public --tag ${Script.channel}`.cwd(dir)
|
await $`npm publish *.tgz --access public --tag ${Script.channel}`.cwd(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function publishDistribution(input: { root: string; name: string; binary: string; packagePrefix: string }) {
|
|
||||||
const binaries: Record<string, string> = {}
|
const binaries: Record<string, string> = {}
|
||||||
for (const filepath of new Bun.Glob("*/package.json").scanSync({ cwd: input.root })) {
|
for (const filepath of new Bun.Glob("*/package.json").scanSync({ cwd: "./dist" })) {
|
||||||
const item = await Bun.file(`${input.root}/${filepath}`).json()
|
const item = await Bun.file(`./dist/${filepath}`).json()
|
||||||
if (!item.name.startsWith(input.packagePrefix)) continue
|
|
||||||
binaries[item.name] = item.version
|
binaries[item.name] = item.version
|
||||||
}
|
}
|
||||||
console.log(input.name, "binaries", binaries)
|
console.log("binaries", binaries)
|
||||||
const versions = new Set(Object.values(binaries))
|
const version = Object.values(binaries)[0]
|
||||||
if (versions.size > 1) throw new Error(`Binary package versions do not match for ${input.name}`)
|
const name = pkg.name
|
||||||
const version = versions.values().next().value
|
|
||||||
if (!version) throw new Error(`No binary packages found for ${input.name}`)
|
|
||||||
|
|
||||||
await $`mkdir -p ${input.root}/${input.name}/bin`
|
await $`mkdir -p ./dist/${name}/bin`
|
||||||
await $`cp ./bin/opencode2.cjs ${input.root}/${input.name}/bin/${input.binary}`
|
await $`cp ./bin/opencode2.cjs ./dist/${name}/bin/opencode2`
|
||||||
await Bun.file(`${input.root}/${input.name}/package.json`).write(
|
await Bun.file(`./dist/${name}/package.json`).write(
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
{
|
{
|
||||||
name: input.name,
|
name,
|
||||||
bin: { [input.binary]: `./bin/${input.binary}` },
|
bin: { opencode2: "./bin/opencode2" },
|
||||||
version,
|
version,
|
||||||
license: pkg.license,
|
license: pkg.license,
|
||||||
repository: { type: "git", url: "git+https://github.com/anomalyco/opencode.git" },
|
repository: { type: "git", url: "git+https://github.com/anomalyco/opencode.git" },
|
||||||
@@ -52,21 +48,7 @@ async function publishDistribution(input: { root: string; name: string; binary:
|
|||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Object.entries(binaries).map(([name, version]) =>
|
Object.entries(binaries).map(([name, version]) =>
|
||||||
publish(`${input.root}/${name.replace("@opencode-ai/", "")}`, name, version),
|
publish(`./dist/${name.replace("@opencode-ai/", "")}`, name, version),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
await publish(`${input.root}/${input.name}`, input.name, version)
|
await publish(`./dist/${name}`, name, version)
|
||||||
}
|
|
||||||
|
|
||||||
await publishDistribution({
|
|
||||||
root: "./dist",
|
|
||||||
name: pkg.name,
|
|
||||||
binary: "opencode2",
|
|
||||||
packagePrefix: "@opencode-ai/cli-",
|
|
||||||
})
|
|
||||||
await publishDistribution({
|
|
||||||
root: "./dist/node",
|
|
||||||
name: "opencode-node",
|
|
||||||
binary: "opencode2-node",
|
|
||||||
packagePrefix: "@opencode-ai/cli-node-",
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -7,10 +7,9 @@ import fs from "node:fs/promises"
|
|||||||
import os from "node:os"
|
import os from "node:os"
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
|
|
||||||
const nodeBuild = process.argv.includes("--node")
|
const target = `cli-${process.platform === "win32" ? "windows" : process.platform}-${process.arch}`
|
||||||
const target = `cli${nodeBuild ? "-node" : ""}-${process.platform === "win32" ? "windows" : process.platform}-${process.arch}`
|
const directory = path.join(import.meta.dir, "..", "dist", target, "bin")
|
||||||
const directory = path.join(import.meta.dir, "..", "dist", ...(nodeBuild ? ["node"] : []), target, "bin")
|
const binary = path.join(directory, `opencode2${process.platform === "win32" ? ".exe" : ""}`)
|
||||||
const binary = path.join(directory, `opencode2${nodeBuild ? "-node" : ""}${process.platform === "win32" ? ".exe" : ""}`)
|
|
||||||
if (!(await Bun.file(binary).exists())) throw new Error(`Missing compiled CLI in ${directory}`)
|
if (!(await Bun.file(binary).exists())) throw new Error(`Missing compiled CLI in ${directory}`)
|
||||||
|
|
||||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-service-smoke-"))
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-service-smoke-"))
|
||||||
|
|||||||
@@ -66,17 +66,6 @@ export const Commands = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCO
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
Spec.make("auth", {
|
|
||||||
description: "Manage authentication",
|
|
||||||
commands: [
|
|
||||||
Spec.make("connect", {
|
|
||||||
description: "Connect to a wellknown authentication provider",
|
|
||||||
params: {
|
|
||||||
url: Argument.string("url").pipe(Argument.withDescription("Wellknown provider URL")),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Spec.make("mcp", {
|
Spec.make("mcp", {
|
||||||
description: "Manage MCP (Model Context Protocol) servers",
|
description: "Manage MCP (Model Context Protocol) servers",
|
||||||
commands: [
|
commands: [
|
||||||
@@ -189,7 +178,10 @@ export const Commands = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCO
|
|||||||
Flag.atMost(100),
|
Flag.atMost(100),
|
||||||
),
|
),
|
||||||
title: Flag.string("title").pipe(Flag.withDescription("Session title"), Flag.optional),
|
title: Flag.string("title").pipe(Flag.withDescription("Session title"), Flag.optional),
|
||||||
thinking: Flag.boolean("thinking").pipe(Flag.withDescription("Show thinking blocks"), Flag.withDefault(false)),
|
thinking: Flag.boolean("thinking").pipe(
|
||||||
|
Flag.withDescription("Show thinking blocks"),
|
||||||
|
Flag.withDefault(false),
|
||||||
|
),
|
||||||
auto: Flag.boolean("auto").pipe(
|
auto: Flag.boolean("auto").pipe(
|
||||||
Flag.withDescription("Auto-approve permissions that are not explicitly denied"),
|
Flag.withDescription("Auto-approve permissions that are not explicitly denied"),
|
||||||
Flag.withDefault(false),
|
Flag.withDefault(false),
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
import { EOL } from "node:os"
|
|
||||||
import { Effect } from "effect"
|
|
||||||
import { Service } from "@opencode-ai/client/effect/service"
|
|
||||||
import { OpenCode, type IntegrationCommandStatusOutput, type OpenCodeClient } from "@opencode-ai/client/promise"
|
|
||||||
import { Commands } from "../../commands"
|
|
||||||
import { Runtime } from "../../../framework/runtime"
|
|
||||||
import { ServiceConfig } from "../../../services/service-config"
|
|
||||||
|
|
||||||
const location = { directory: process.cwd() }
|
|
||||||
|
|
||||||
export default Runtime.handler(
|
|
||||||
Commands.commands.auth.commands.connect,
|
|
||||||
Effect.fn("cli.auth.connect")(function* (input) {
|
|
||||||
process.stdout.write("Connecting..." + EOL + EOL)
|
|
||||||
const endpoint = yield* Service.ensure(yield* ServiceConfig.options())
|
|
||||||
const client = OpenCode.make({ baseUrl: endpoint.url, headers: Service.headers(endpoint) })
|
|
||||||
yield* request(() => client.integration.wellknown.add({ url: input.url, location }))
|
|
||||||
const integrationID = input.url.replace(/\/+$/, "")
|
|
||||||
const started = yield* request(() =>
|
|
||||||
client.integration.command.connect({ integrationID, methodID: "login", location }),
|
|
||||||
)
|
|
||||||
yield* Effect.addFinalizer(() =>
|
|
||||||
request(() =>
|
|
||||||
client.integration.command.cancel({ integrationID, attemptID: started.data.attemptID, location }),
|
|
||||||
).pipe(Effect.ignore),
|
|
||||||
)
|
|
||||||
|
|
||||||
const status = yield* wait(client, integrationID, started.data.attemptID)
|
|
||||||
if (status.status === "failed") return yield* Effect.fail(new Error(status.message))
|
|
||||||
if (status.status === "expired") return yield* Effect.fail(new Error("Authentication expired"))
|
|
||||||
process.stdout.write("Connected" + EOL)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
const wait = (
|
|
||||||
client: OpenCodeClient,
|
|
||||||
integrationID: string,
|
|
||||||
attemptID: string,
|
|
||||||
shown = false,
|
|
||||||
): Effect.Effect<Exclude<IntegrationCommandStatusOutput["data"], { status: "pending" }>, unknown> =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
const response = yield* request(() => client.integration.command.status({ integrationID, attemptID, location }))
|
|
||||||
if (response.data.status !== "pending") return response.data
|
|
||||||
const output = response.data.message?.trim()
|
|
||||||
if (!shown && output) process.stdout.write(output + EOL + EOL)
|
|
||||||
yield* Effect.sleep(500)
|
|
||||||
return yield* wait(client, integrationID, attemptID, shown || !!output)
|
|
||||||
})
|
|
||||||
|
|
||||||
function request<A>(task: () => Promise<A>) {
|
|
||||||
return Effect.tryPromise({ try: task, catch: (cause) => cause })
|
|
||||||
}
|
|
||||||
@@ -46,7 +46,7 @@ const login = Effect.fn("cli.console.login.run")(function* (timeline: TimelineHo
|
|||||||
|
|
||||||
yield* request(() => timeline.pending("Starting authorization..."))
|
yield* request(() => timeline.pending("Starting authorization..."))
|
||||||
const started = yield* request((signal) =>
|
const started = yield* request((signal) =>
|
||||||
client.integration.oauth.connect(
|
client.integration.connect.oauth(
|
||||||
{
|
{
|
||||||
integrationID,
|
integrationID,
|
||||||
methodID: method.id,
|
methodID: method.id,
|
||||||
@@ -59,8 +59,8 @@ const login = Effect.fn("cli.console.login.run")(function* (timeline: TimelineHo
|
|||||||
const attempt = started.data
|
const attempt = started.data
|
||||||
yield* Effect.addFinalizer(() =>
|
yield* Effect.addFinalizer(() =>
|
||||||
request(() =>
|
request(() =>
|
||||||
client.integration.oauth.cancel(
|
client.integration.attempt.cancel(
|
||||||
{ integrationID, attemptID: attempt.attemptID, location },
|
{ attemptID: attempt.attemptID, location },
|
||||||
{ signal: AbortSignal.timeout(5_000) },
|
{ signal: AbortSignal.timeout(5_000) },
|
||||||
),
|
),
|
||||||
).pipe(Effect.ignore),
|
).pipe(Effect.ignore),
|
||||||
@@ -75,7 +75,7 @@ const login = Effect.fn("cli.console.login.run")(function* (timeline: TimelineHo
|
|||||||
}).pipe(Effect.ignore)
|
}).pipe(Effect.ignore)
|
||||||
yield* request(() => timeline.pending("Waiting for authorization..."))
|
yield* request(() => timeline.pending("Waiting for authorization..."))
|
||||||
|
|
||||||
const status = yield* waitForConsoleLogin(client, integrationID, attempt.attemptID)
|
const status = yield* waitForConsoleLogin(client, attempt.attemptID)
|
||||||
if (status.status === "failed") yield* Effect.fail(new Error(status.message))
|
if (status.status === "failed") yield* Effect.fail(new Error(status.message))
|
||||||
if (status.status === "expired") yield* Effect.fail(new Error("Device code expired"))
|
if (status.status === "expired") yield* Effect.fail(new Error("Device code expired"))
|
||||||
|
|
||||||
@@ -85,12 +85,11 @@ const login = Effect.fn("cli.console.login.run")(function* (timeline: TimelineHo
|
|||||||
|
|
||||||
const waitForConsoleLogin = Effect.fn("cli.console.login.wait")(function* (
|
const waitForConsoleLogin = Effect.fn("cli.console.login.wait")(function* (
|
||||||
client: OpenCodeClient,
|
client: OpenCodeClient,
|
||||||
integrationID: string,
|
|
||||||
attemptID: string,
|
attemptID: string,
|
||||||
) {
|
) {
|
||||||
while (true) {
|
while (true) {
|
||||||
const response = yield* request((signal) =>
|
const response = yield* request((signal) =>
|
||||||
client.integration.oauth.status({ integrationID, attemptID, location }, { signal }),
|
client.integration.attempt.status({ attemptID, location }, { signal }),
|
||||||
)
|
)
|
||||||
if (response.data.status !== "pending") return response.data
|
if (response.data.status !== "pending") return response.data
|
||||||
yield* Effect.sleep(500)
|
yield* Effect.sleep(500)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { EOL } from "node:os"
|
import { EOL } from "node:os"
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
import { readFile, stat, writeFile } from "node:fs/promises"
|
|
||||||
import { Effect, Option } from "effect"
|
import { Effect, Option } from "effect"
|
||||||
import { applyEdits, modify } from "jsonc-parser"
|
import { applyEdits, modify } from "jsonc-parser"
|
||||||
import { Global } from "@opencode-ai/core/global"
|
import { Global } from "@opencode-ai/core/global"
|
||||||
@@ -36,7 +35,7 @@ export default Runtime.handler(
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
export async function resolveConfigPath(directory: string) {
|
async function resolveConfigPath(directory: string) {
|
||||||
const candidates = [
|
const candidates = [
|
||||||
path.join(directory, "opencode.json"),
|
path.join(directory, "opencode.json"),
|
||||||
path.join(directory, "opencode.jsonc"),
|
path.join(directory, "opencode.jsonc"),
|
||||||
@@ -44,24 +43,16 @@ export async function resolveConfigPath(directory: string) {
|
|||||||
path.join(directory, ".opencode", "opencode.jsonc"),
|
path.join(directory, ".opencode", "opencode.jsonc"),
|
||||||
]
|
]
|
||||||
for (const candidate of candidates) {
|
for (const candidate of candidates) {
|
||||||
if (
|
if (await Bun.file(candidate).exists()) return candidate
|
||||||
await stat(candidate).then(
|
|
||||||
(info) => info.isFile(),
|
|
||||||
() => false,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return candidate
|
|
||||||
}
|
}
|
||||||
return candidates[0]
|
return candidates[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
async function write(configPath: string, name: string, server: unknown) {
|
async function write(configPath: string, name: string, server: unknown) {
|
||||||
const text = await readFile(configPath, "utf8").catch((error) => {
|
const file = Bun.file(configPath)
|
||||||
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") return "{}"
|
const text = (await file.exists()) ? await file.text() : "{}"
|
||||||
throw error
|
|
||||||
})
|
|
||||||
const edits = modify(text, ["mcp", "servers", name], server, {
|
const edits = modify(text, ["mcp", "servers", name], server, {
|
||||||
formattingOptions: { tabSize: 2, insertSpaces: true },
|
formattingOptions: { tabSize: 2, insertSpaces: true },
|
||||||
})
|
})
|
||||||
await writeFile(configPath, applyEdits(text, edits))
|
await Bun.write(configPath, applyEdits(text, edits))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default Runtime.handler(
|
|||||||
return yield* Effect.fail(new Error(`MCP server "${input.name}" is not an OAuth-capable remote server`))
|
return yield* Effect.fail(new Error(`MCP server "${input.name}" is not an OAuth-capable remote server`))
|
||||||
|
|
||||||
const started = yield* Effect.promise(() =>
|
const started = yield* Effect.promise(() =>
|
||||||
client.integration.oauth.connect({ integrationID: integration.id, methodID: method.id, inputs: {}, location }),
|
client.integration.connect.oauth({ integrationID: integration.id, methodID: method.id, inputs: {}, location }),
|
||||||
)
|
)
|
||||||
const attempt = started.data
|
const attempt = started.data
|
||||||
if (attempt.mode === "code")
|
if (attempt.mode === "code")
|
||||||
@@ -40,7 +40,7 @@ export default Runtime.handler(
|
|||||||
|
|
||||||
process.stdout.write(attempt.instructions + EOL + attempt.url + EOL)
|
process.stdout.write(attempt.instructions + EOL + attempt.url + EOL)
|
||||||
|
|
||||||
const result = yield* poll(client, integration.id, attempt.attemptID)
|
const result = yield* poll(client, attempt.attemptID)
|
||||||
if (result.status === "complete") {
|
if (result.status === "complete") {
|
||||||
process.stdout.write(`Authenticated with ${input.name}` + EOL)
|
process.stdout.write(`Authenticated with ${input.name}` + EOL)
|
||||||
return
|
return
|
||||||
@@ -52,16 +52,15 @@ export default Runtime.handler(
|
|||||||
|
|
||||||
const poll = (
|
const poll = (
|
||||||
client: OpenCodeClient,
|
client: OpenCodeClient,
|
||||||
integrationID: string,
|
|
||||||
attemptID: string,
|
attemptID: string,
|
||||||
): Effect.Effect<Exclude<IntegrationAttemptStatus, { status: "pending" }>> =>
|
): Effect.Effect<Exclude<IntegrationAttemptStatus, { status: "pending" }>> =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const status = yield* Effect.promise(() =>
|
const status = yield* Effect.promise(() => client.integration.attempt.status({ attemptID, location })).pipe(
|
||||||
client.integration.oauth.status({ integrationID, attemptID, location }),
|
Effect.map((result) => result.data),
|
||||||
).pipe(Effect.map((result) => result.data))
|
)
|
||||||
if (status.status === "pending") {
|
if (status.status === "pending") {
|
||||||
yield* Effect.sleep("1 second")
|
yield* Effect.sleep("1 second")
|
||||||
return yield* poll(client, integrationID, attemptID)
|
return yield* poll(client, attemptID)
|
||||||
}
|
}
|
||||||
return status
|
return status
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { ServerProcess } from "../../server-process"
|
|||||||
|
|
||||||
export default Runtime.handler(
|
export default Runtime.handler(
|
||||||
Commands.commands.serve,
|
Commands.commands.serve,
|
||||||
Effect.fnUntraced(function* (input) {
|
Effect.fn("cli.serve")(function* (input) {
|
||||||
if (input.service && input.stdio) return yield* Effect.fail(new Error("--service and --stdio cannot be combined"))
|
if (input.service && input.stdio) return yield* Effect.fail(new Error("--service and --stdio cannot be combined"))
|
||||||
return yield* ServerProcess.run({
|
return yield* ServerProcess.run({
|
||||||
mode: input.service ? "service" : input.stdio ? "stdio" : "default",
|
mode: input.service ? "service" : input.stdio ? "stdio" : "default",
|
||||||
|
|||||||
@@ -17,9 +17,6 @@ import { Npm } from "@opencode-ai/core/npm"
|
|||||||
const Handlers = Runtime.handlers(Commands, {
|
const Handlers = Runtime.handlers(Commands, {
|
||||||
$: () => import("./commands/handlers/default"),
|
$: () => import("./commands/handlers/default"),
|
||||||
api: () => import("./commands/handlers/api"),
|
api: () => import("./commands/handlers/api"),
|
||||||
auth: {
|
|
||||||
connect: () => import("./commands/handlers/auth/connect"),
|
|
||||||
},
|
|
||||||
debug: {
|
debug: {
|
||||||
agents: () => import("./commands/handlers/debug/agents"),
|
agents: () => import("./commands/handlers/debug/agents"),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -633,12 +633,6 @@ export function RunSubagentSelectBody(props: {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.name.toLowerCase() === "up" && menu.selected() === 0) {
|
|
||||||
event.preventDefault()
|
|
||||||
props.onClose()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
handleKey({ event, menu, field: () => field, setQuery, select, close: props.onClose })
|
handleKey({ event, menu, field: () => field, setQuery, select, close: props.onClose })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { useTerminalDimensions } from "@opentui/solid"
|
|||||||
import { createEffect, createMemo, createSignal, type Accessor } from "solid-js"
|
import { createEffect, createMemo, createSignal, type Accessor } from "solid-js"
|
||||||
import { transparent, type RunFooterTheme } from "./theme"
|
import { transparent, type RunFooterTheme } from "./theme"
|
||||||
import { Locale } from "@opencode-ai/tui/util/locale"
|
import { Locale } from "@opencode-ai/tui/util/locale"
|
||||||
import { stringWidth } from "@opencode-ai/tui/util/string-width"
|
|
||||||
|
|
||||||
export const FOOTER_MENU_ROWS = 8
|
export const FOOTER_MENU_ROWS = 8
|
||||||
|
|
||||||
@@ -197,7 +196,7 @@ export function RunFooterMenu(props: {
|
|||||||
...props
|
...props
|
||||||
.items()
|
.items()
|
||||||
.filter((item) => item.description)
|
.filter((item) => item.description)
|
||||||
.map((item) => stringWidth(item.display)),
|
.map((item) => Bun.stringWidth(item.display)),
|
||||||
)
|
)
|
||||||
return width === 0 ? 0 : width + 2
|
return width === 0 ? 0 : width + 2
|
||||||
})
|
})
|
||||||
@@ -206,14 +205,14 @@ export function RunFooterMenu(props: {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return " ".repeat(Math.max(1, descriptionColumn() - stringWidth(item.display)))
|
return " ".repeat(Math.max(1, descriptionColumn() - Bun.stringWidth(item.display)))
|
||||||
}
|
}
|
||||||
const descriptionText = (item: RunFooterMenuItem) => {
|
const descriptionText = (item: RunFooterMenuItem) => {
|
||||||
if (!item.description) {
|
if (!item.description) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const footerWidth = item.footer ? stringWidth(item.footer) + 1 : 0
|
const footerWidth = item.footer ? Bun.stringWidth(item.footer) + 1 : 0
|
||||||
const available =
|
const available =
|
||||||
term().width -
|
term().width -
|
||||||
(border() ? 1 : 0) -
|
(border() ? 1 : 0) -
|
||||||
|
|||||||
@@ -5,15 +5,14 @@
|
|||||||
// It produces a PromptState that RunPromptBody renders as a slim single-line
|
// It produces a PromptState that RunPromptBody renders as a slim single-line
|
||||||
// composer while the footer view renders any active menus below it.
|
// composer while the footer view renders any active menus below it.
|
||||||
/** @jsxImportSource @opentui/solid */
|
/** @jsxImportSource @opentui/solid */
|
||||||
|
import { pathToFileURL } from "bun"
|
||||||
import { StyledText, fg, type ColorInput, type KeyEvent, type TextareaRenderable } from "@opentui/core"
|
import { StyledText, fg, type ColorInput, type KeyEvent, type TextareaRenderable } from "@opentui/core"
|
||||||
import { useRenderer } from "@opentui/solid"
|
import { useRenderer } from "@opentui/solid"
|
||||||
import { normalizePromptContent } from "@opencode-ai/tui/prompt/content"
|
import { normalizePromptContent } from "@opencode-ai/tui/prompt/content"
|
||||||
import fuzzysort from "fuzzysort"
|
import fuzzysort from "fuzzysort"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { pathToFileURL } from "node:url"
|
|
||||||
import { createEffect, createMemo, createResource, createSignal, onCleanup, onMount, type Accessor } from "solid-js"
|
import { createEffect, createMemo, createResource, createSignal, onCleanup, onMount, type Accessor } from "solid-js"
|
||||||
import { Locale } from "@opencode-ai/tui/util/locale"
|
import { Locale } from "@opencode-ai/tui/util/locale"
|
||||||
import { stringWidth } from "@opencode-ai/tui/util/string-width"
|
|
||||||
import {
|
import {
|
||||||
createPromptHistory,
|
createPromptHistory,
|
||||||
displayCharAt,
|
displayCharAt,
|
||||||
@@ -24,7 +23,7 @@ import {
|
|||||||
movePromptHistory,
|
movePromptHistory,
|
||||||
pushPromptHistory,
|
pushPromptHistory,
|
||||||
} from "./prompt.shared"
|
} from "./prompt.shared"
|
||||||
import { Keymap } from "@opencode-ai/tui/context/keymap"
|
import { OPENCODE_BASE_MODE, useBindings } from "@opencode-ai/tui/keymap"
|
||||||
import { realignEditorPromptParts, resolveEditorSlashValue } from "./prompt.editor"
|
import { realignEditorPromptParts, resolveEditorSlashValue } from "./prompt.editor"
|
||||||
import { FOOTER_MENU_ROWS, createFooterMenuState, type RunFooterMenuItem } from "./footer.menu"
|
import { FOOTER_MENU_ROWS, createFooterMenuState, type RunFooterMenuItem } from "./footer.menu"
|
||||||
import type { RunFooterTheme } from "./theme"
|
import type { RunFooterTheme } from "./theme"
|
||||||
@@ -603,7 +602,7 @@ export function createPromptState(input: PromptInput): PromptState {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const restore = (value: RunPrompt, cursor = stringWidth(value.text)) => {
|
const restore = (value: RunPrompt, cursor = Bun.stringWidth(value.text)) => {
|
||||||
draft = clonePrompt(value)
|
draft = clonePrompt(value)
|
||||||
setShell(value.mode === "shell")
|
setShell(value.mode === "shell")
|
||||||
if (!area || area.isDestroyed) {
|
if (!area || area.isDestroyed) {
|
||||||
@@ -613,7 +612,7 @@ export function createPromptState(input: PromptInput): PromptState {
|
|||||||
hide()
|
hide()
|
||||||
area.setText(value.text)
|
area.setText(value.text)
|
||||||
restoreParts(value.parts)
|
restoreParts(value.parts)
|
||||||
area.cursorOffset = Math.min(cursor, stringWidth(area.plainText))
|
area.cursorOffset = Math.min(cursor, Bun.stringWidth(area.plainText))
|
||||||
scheduleRows()
|
scheduleRows()
|
||||||
area.focus()
|
area.focus()
|
||||||
}
|
}
|
||||||
@@ -644,7 +643,7 @@ export function createPromptState(input: PromptInput): PromptState {
|
|||||||
area.setText(text)
|
area.setText(text)
|
||||||
clearParts()
|
clearParts()
|
||||||
draft = shell() ? { text: area.plainText, parts: [], mode: "shell" } : { text: area.plainText, parts: [] }
|
draft = shell() ? { text: area.plainText, parts: [], mode: "shell" } : { text: area.plainText, parts: [] }
|
||||||
area.cursorOffset = Math.min(stringWidth(text), stringWidth(area.plainText))
|
area.cursorOffset = Math.min(Bun.stringWidth(text), Bun.stringWidth(area.plainText))
|
||||||
scheduleRows()
|
scheduleRows()
|
||||||
area.focus()
|
area.focus()
|
||||||
}
|
}
|
||||||
@@ -778,7 +777,7 @@ export function createPromptState(input: PromptInput): PromptState {
|
|||||||
if (move(dir, event)) return
|
if (move(dir, event)) return
|
||||||
if (!area || area.isDestroyed) return false
|
if (!area || area.isDestroyed) return false
|
||||||
|
|
||||||
const endOffset = stringWidth(area.plainText)
|
const endOffset = Bun.stringWidth(area.plainText)
|
||||||
if (dir === -1) {
|
if (dir === -1) {
|
||||||
if (area.cursorOffset === 0) return false
|
if (area.cursorOffset === 0) return false
|
||||||
if (area.visualCursor.visualRow === 0) {
|
if (area.visualCursor.visualRow === 0) {
|
||||||
@@ -887,12 +886,16 @@ export function createPromptState(input: PromptInput): PromptState {
|
|||||||
area.cursorOffset = 0
|
area.cursorOffset = 0
|
||||||
const start = area.logicalCursor
|
const start = area.logicalCursor
|
||||||
area.cursorOffset =
|
area.cursorOffset =
|
||||||
shell() || !head ? cursor : local ? stringWidth(area.plainText) : stringWidth(area.plainText.slice(0, head.end))
|
shell() || !head
|
||||||
|
? cursor
|
||||||
|
: local
|
||||||
|
? Bun.stringWidth(area.plainText)
|
||||||
|
: Bun.stringWidth(area.plainText.slice(0, head.end))
|
||||||
const end = area.logicalCursor
|
const end = area.logicalCursor
|
||||||
|
|
||||||
area.deleteRange(start.row, start.col, end.row, end.col)
|
area.deleteRange(start.row, start.col, end.row, end.col)
|
||||||
area.insertText(text)
|
area.insertText(text)
|
||||||
area.cursorOffset = stringWidth(text)
|
area.cursorOffset = Bun.stringWidth(text)
|
||||||
hide()
|
hide()
|
||||||
syncDraft()
|
syncDraft()
|
||||||
if (!shell()) {
|
if (!shell()) {
|
||||||
@@ -917,7 +920,7 @@ export function createPromptState(input: PromptInput): PromptState {
|
|||||||
|
|
||||||
const text = "@" + next.value
|
const text = "@" + next.value
|
||||||
const startOffset = at()
|
const startOffset = at()
|
||||||
const endOffset = startOffset + stringWidth(text)
|
const endOffset = startOffset + Bun.stringWidth(text)
|
||||||
const part = structuredClone(next.part)
|
const part = structuredClone(next.part)
|
||||||
if (part.type === "agent") {
|
if (part.type === "agent") {
|
||||||
part.source = {
|
part.source = {
|
||||||
@@ -990,83 +993,93 @@ export function createPromptState(input: PromptInput): PromptState {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
useBindings(() => ({
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled: baseBindingsEnabled(),
|
enabled: baseBindingsEnabled(),
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
id: "prompt.clear",
|
name: "prompt.clear",
|
||||||
title: "Clear prompt or exit",
|
title: "Clear prompt or exit",
|
||||||
group: "Prompt",
|
category: "Prompt",
|
||||||
run() {
|
run() {
|
||||||
if (requestExit()) return
|
if (requestExit()) return
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
bindings: input.tuiConfig.keybinds.get("prompt.clear"),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
useBindings(() => ({
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled: input.prompt(),
|
enabled: input.prompt(),
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
id: "session.interrupt",
|
name: "session.interrupt",
|
||||||
title: "Interrupt session",
|
title: "Interrupt session",
|
||||||
group: "Session",
|
category: "Session",
|
||||||
run() {
|
run() {
|
||||||
if (input.onInterrupt()) return
|
if (input.onInterrupt()) return
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
bindings: input.tuiConfig.keybinds.get("session.interrupt"),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
useBindings(() => ({
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled: input.prompt() && !visible(),
|
enabled: input.prompt() && !visible(),
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
id: "prompt.editor",
|
name: "prompt.editor",
|
||||||
title: "Open editor",
|
title: "Open editor",
|
||||||
group: "Prompt",
|
category: "Prompt",
|
||||||
run() {
|
run() {
|
||||||
void openEditor()
|
void openEditor()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
bindings: input.tuiConfig.keybinds.get("prompt.editor"),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
useBindings(() => ({
|
||||||
priority: 1,
|
priority: 1,
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled: input.prompt() && !visible(),
|
enabled: input.prompt() && !visible(),
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
id: "prompt.history.previous",
|
name: "prompt.history.previous",
|
||||||
title: "Previous prompt history",
|
title: "Previous prompt history",
|
||||||
group: "Prompt",
|
category: "Prompt",
|
||||||
run(_input: string | undefined, event?: KeyEvent) {
|
run(ctx: { event: KeyEvent }) {
|
||||||
if (!event) return false
|
return historyCommand(-1, ctx.event)
|
||||||
return historyCommand(-1, event)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "prompt.history.next",
|
name: "prompt.history.next",
|
||||||
title: "Next prompt history",
|
title: "Next prompt history",
|
||||||
group: "Prompt",
|
category: "Prompt",
|
||||||
run(_input: string | undefined, event?: KeyEvent) {
|
run(ctx: { event: KeyEvent }) {
|
||||||
if (!event) return false
|
return historyCommand(1, ctx.event)
|
||||||
return historyCommand(1, event)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
bindings: [
|
||||||
|
...input.tuiConfig.keybinds.get("prompt.history.previous"),
|
||||||
|
...input.tuiConfig.keybinds.get("prompt.history.next"),
|
||||||
|
],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
useBindings(() => ({
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled: input.prompt() && !visible(),
|
enabled: input.prompt() && !visible(),
|
||||||
commands: [
|
bindings: [
|
||||||
{
|
{
|
||||||
bind: "!",
|
key: "!",
|
||||||
title: "Shell mode",
|
desc: "Shell mode",
|
||||||
group: "Prompt",
|
group: "Prompt",
|
||||||
run() {
|
cmd() {
|
||||||
if (shell()) return false
|
if (shell()) return false
|
||||||
if (!area || area.isDestroyed) return false
|
if (!area || area.isDestroyed) return false
|
||||||
if (area.cursorOffset !== 0) return false
|
if (area.cursorOffset !== 0) return false
|
||||||
@@ -1076,20 +1089,21 @@ export function createPromptState(input: PromptInput): PromptState {
|
|||||||
],
|
],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
useBindings(() => ({
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled: input.prompt() && shell() && !visible(),
|
enabled: input.prompt() && shell() && !visible(),
|
||||||
commands: [
|
bindings: [
|
||||||
{
|
{
|
||||||
bind: "escape",
|
key: "escape",
|
||||||
title: "Exit shell mode",
|
desc: "Exit shell mode",
|
||||||
group: "Prompt",
|
group: "Prompt",
|
||||||
run: () => setShellMode(false),
|
cmd: () => setShellMode(false),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
bind: "backspace",
|
key: "backspace",
|
||||||
title: "Exit shell mode",
|
desc: "Exit shell mode",
|
||||||
group: "Prompt",
|
group: "Prompt",
|
||||||
run() {
|
cmd() {
|
||||||
if (!area || area.isDestroyed) return false
|
if (!area || area.isDestroyed) return false
|
||||||
if (area.cursorOffset !== 0) return false
|
if (area.cursorOffset !== 0) return false
|
||||||
setShellMode(false)
|
setShellMode(false)
|
||||||
@@ -1098,31 +1112,32 @@ export function createPromptState(input: PromptInput): PromptState {
|
|||||||
],
|
],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
useBindings(() => ({
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled: input.prompt() && visible(),
|
enabled: input.prompt() && visible(),
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
id: "prompt.autocomplete.prev",
|
name: "prompt.autocomplete.prev",
|
||||||
title: "Previous autocomplete item",
|
title: "Previous autocomplete item",
|
||||||
group: "Autocomplete",
|
category: "Autocomplete",
|
||||||
run: () => menu.move(-1),
|
run: () => menu.move(-1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "prompt.autocomplete.next",
|
name: "prompt.autocomplete.next",
|
||||||
title: "Next autocomplete item",
|
title: "Next autocomplete item",
|
||||||
group: "Autocomplete",
|
category: "Autocomplete",
|
||||||
run: () => menu.move(1),
|
run: () => menu.move(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "prompt.autocomplete.hide",
|
name: "prompt.autocomplete.hide",
|
||||||
title: "Hide autocomplete",
|
title: "Hide autocomplete",
|
||||||
group: "Autocomplete",
|
category: "Autocomplete",
|
||||||
run: cancelAutocomplete,
|
run: cancelAutocomplete,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "prompt.autocomplete.select",
|
name: "prompt.autocomplete.select",
|
||||||
title: "Select autocomplete item",
|
title: "Select autocomplete item",
|
||||||
group: "Autocomplete",
|
category: "Autocomplete",
|
||||||
run() {
|
run() {
|
||||||
if (mode() === "slash" && options().length === 0) {
|
if (mode() === "slash" && options().length === 0) {
|
||||||
hide()
|
hide()
|
||||||
@@ -1132,9 +1147,9 @@ export function createPromptState(input: PromptInput): PromptState {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "prompt.autocomplete.complete",
|
name: "prompt.autocomplete.complete",
|
||||||
title: "Complete autocomplete item",
|
title: "Complete autocomplete item",
|
||||||
group: "Autocomplete",
|
category: "Autocomplete",
|
||||||
run() {
|
run() {
|
||||||
if (mode() === "slash" && options().length === 0) {
|
if (mode() === "slash" && options().length === 0) {
|
||||||
hide()
|
hide()
|
||||||
@@ -1149,6 +1164,13 @@ export function createPromptState(input: PromptInput): PromptState {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
bindings: [
|
||||||
|
"prompt.autocomplete.prev",
|
||||||
|
"prompt.autocomplete.next",
|
||||||
|
"prompt.autocomplete.hide",
|
||||||
|
"prompt.autocomplete.select",
|
||||||
|
"prompt.autocomplete.complete",
|
||||||
|
].flatMap((command) => input.tuiConfig.keybinds.get(command)),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const onKeyDown = (event: KeyEvent) => {
|
const onKeyDown = (event: KeyEvent) => {
|
||||||
|
|||||||
@@ -24,11 +24,12 @@
|
|||||||
// Ctrl-c clears a live prompt draft first; otherwise interrupt and exit use a
|
// Ctrl-c clears a live prompt draft first; otherwise interrupt and exit use a
|
||||||
// two-press pattern where the first press shows a hint and the second press
|
// two-press pattern where the first press shows a hint and the second press
|
||||||
// within 5 seconds actually fires the action.
|
// within 5 seconds actually fires the action.
|
||||||
import { CliRenderEvents, type CliRenderer, type TreeSitterClient } from "@opentui/core"
|
import { CliRenderEvents, type CliRenderer, type KeyEvent, type Renderable, type TreeSitterClient } from "@opentui/core"
|
||||||
|
import type { Keymap } from "@opentui/keymap"
|
||||||
import { render } from "@opentui/solid"
|
import { render } from "@opentui/solid"
|
||||||
import { createComponent, createSignal, type Accessor, type Setter } from "solid-js"
|
import { createComponent, createSignal, type Accessor, type Setter } from "solid-js"
|
||||||
import { createStore, reconcile } from "solid-js/store"
|
import { createStore, reconcile } from "solid-js/store"
|
||||||
import { Keymap } from "@opencode-ai/tui/context/keymap"
|
import { OpencodeKeymapProvider } from "@opencode-ai/tui/keymap"
|
||||||
import { RUN_COMMAND_PANEL_ROWS, RUN_SUBAGENT_PANEL_ROWS } from "./footer.command"
|
import { RUN_COMMAND_PANEL_ROWS, RUN_SUBAGENT_PANEL_ROWS } from "./footer.command"
|
||||||
import { SUBAGENT_INSPECTOR_ROWS } from "./footer.subagent"
|
import { SUBAGENT_INSPECTOR_ROWS } from "./footer.subagent"
|
||||||
import { PROMPT_MAX_ROWS, TEXTAREA_MIN_ROWS } from "./footer.prompt"
|
import { PROMPT_MAX_ROWS, TEXTAREA_MIN_ROWS } from "./footer.prompt"
|
||||||
@@ -81,6 +82,7 @@ type RunFooterOptions = {
|
|||||||
first: boolean
|
first: boolean
|
||||||
history?: RunPrompt[]
|
history?: RunPrompt[]
|
||||||
theme: RunTheme
|
theme: RunTheme
|
||||||
|
keymap: Keymap<Renderable, KeyEvent>
|
||||||
tuiConfig: RunTuiConfig
|
tuiConfig: RunTuiConfig
|
||||||
diffStyle: RunDiffStyle
|
diffStyle: RunDiffStyle
|
||||||
onPermissionReply: (input: PermissionReply) => void | Promise<void>
|
onPermissionReply: (input: PermissionReply) => void | Promise<void>
|
||||||
@@ -303,8 +305,8 @@ export class RunFooter implements FooterApi {
|
|||||||
const footer = this
|
const footer = this
|
||||||
void render(
|
void render(
|
||||||
() =>
|
() =>
|
||||||
createComponent(Keymap.Provider, {
|
createComponent(OpencodeKeymapProvider, {
|
||||||
config: options.tuiConfig,
|
keymap: options.keymap,
|
||||||
get children() {
|
get children() {
|
||||||
return createComponent(RunFooterView, {
|
return createComponent(RunFooterView, {
|
||||||
directory: options.directory,
|
directory: options.directory,
|
||||||
|
|||||||
@@ -27,8 +27,14 @@ import { RunPromptBody, createPromptState } from "./footer.prompt"
|
|||||||
import { RunPermissionBody } from "./footer.permission"
|
import { RunPermissionBody } from "./footer.permission"
|
||||||
import { RunQuestionBody } from "./footer.question"
|
import { RunQuestionBody } from "./footer.question"
|
||||||
import { footerWidthPolicy } from "./footer.width"
|
import { footerWidthPolicy } from "./footer.width"
|
||||||
import { Keymap } from "@opencode-ai/tui/context/keymap"
|
import {
|
||||||
|
OPENCODE_BASE_MODE,
|
||||||
|
formatKeyBindings,
|
||||||
|
formatKeySequence,
|
||||||
|
useBindings,
|
||||||
|
useKeymapSelector,
|
||||||
|
type OpenTuiKeymap,
|
||||||
|
} from "@opencode-ai/tui/keymap"
|
||||||
import type {
|
import type {
|
||||||
FooterPromptRoute,
|
FooterPromptRoute,
|
||||||
FooterQueuedPrompt,
|
FooterQueuedPrompt,
|
||||||
@@ -171,15 +177,75 @@ export function RunFooterView(props: RunFooterViewProps) {
|
|||||||
const current = route()
|
const current = route()
|
||||||
return current.type === "subagent" ? subagent().details[current.sessionID] : undefined
|
return current.type === "subagent" ? subagent().details[current.sessionID] : undefined
|
||||||
})
|
})
|
||||||
const shortcuts = Keymap.useShortcuts()
|
const command = useKeymapSelector(
|
||||||
const command = () => shortcuts.get("command.palette.show") ?? ""
|
(keymap: OpenTuiKeymap) =>
|
||||||
const subagentShortcut = () => shortcuts.get("session.child.first") ?? ""
|
formatKeySequence(
|
||||||
const queuedShortcut = () => shortcuts.get("session.queued_prompts") ?? ""
|
keymap
|
||||||
const backgroundShortcut = () => shortcuts.get("session.background") ?? ""
|
.getCommandBindings({ visibility: "registered", commands: ["command.palette.show"] })
|
||||||
const subagentInterruptShortcut = () => shortcuts.get("subagent.interrupt") ?? ""
|
.get("command.palette.show")?.[0]?.sequence,
|
||||||
const interrupt = () => shortcuts.get("session.interrupt") ?? ""
|
props.tuiConfig,
|
||||||
const variantCycle = () => shortcuts.all("variant.cycle") ?? ""
|
) ?? "",
|
||||||
const clearShortcut = () => shortcuts.get("prompt.clear") ?? ""
|
)
|
||||||
|
const subagentShortcut = useKeymapSelector(
|
||||||
|
(keymap: OpenTuiKeymap) =>
|
||||||
|
formatKeySequence(
|
||||||
|
keymap
|
||||||
|
.getCommandBindings({ visibility: "registered", commands: ["session.child.first"] })
|
||||||
|
.get("session.child.first")?.[0]?.sequence,
|
||||||
|
props.tuiConfig,
|
||||||
|
) ?? "",
|
||||||
|
)
|
||||||
|
const queuedShortcut = useKeymapSelector(
|
||||||
|
(keymap: OpenTuiKeymap) =>
|
||||||
|
formatKeySequence(
|
||||||
|
keymap
|
||||||
|
.getCommandBindings({ visibility: "registered", commands: ["session.queued_prompts"] })
|
||||||
|
.get("session.queued_prompts")?.[0]?.sequence,
|
||||||
|
props.tuiConfig,
|
||||||
|
) ?? "",
|
||||||
|
)
|
||||||
|
const backgroundShortcut = useKeymapSelector(
|
||||||
|
(keymap: OpenTuiKeymap) =>
|
||||||
|
formatKeySequence(
|
||||||
|
keymap
|
||||||
|
.getCommandBindings({ visibility: "registered", commands: ["session.background"] })
|
||||||
|
.get("session.background")?.[0]?.sequence,
|
||||||
|
props.tuiConfig,
|
||||||
|
) ?? "",
|
||||||
|
)
|
||||||
|
const subagentInterruptShortcut = useKeymapSelector(
|
||||||
|
(keymap: OpenTuiKeymap) =>
|
||||||
|
formatKeySequence(
|
||||||
|
keymap
|
||||||
|
.getCommandBindings({ visibility: "registered", commands: ["subagent.interrupt"] })
|
||||||
|
.get("subagent.interrupt")?.[0]?.sequence,
|
||||||
|
props.tuiConfig,
|
||||||
|
) ?? "",
|
||||||
|
)
|
||||||
|
const interrupt = useKeymapSelector(
|
||||||
|
(keymap: OpenTuiKeymap) =>
|
||||||
|
formatKeySequence(
|
||||||
|
keymap
|
||||||
|
.getCommandBindings({ visibility: "registered", commands: ["session.interrupt"] })
|
||||||
|
.get("session.interrupt")?.[0]?.sequence,
|
||||||
|
props.tuiConfig,
|
||||||
|
) ?? "",
|
||||||
|
)
|
||||||
|
const variantCycle = useKeymapSelector(
|
||||||
|
(keymap: OpenTuiKeymap) =>
|
||||||
|
formatKeyBindings(
|
||||||
|
keymap.getCommandBindings({ visibility: "registered", commands: ["variant.cycle"] }).get("variant.cycle"),
|
||||||
|
props.tuiConfig,
|
||||||
|
) ?? "",
|
||||||
|
)
|
||||||
|
const clearShortcut = useKeymapSelector(
|
||||||
|
(keymap: OpenTuiKeymap) =>
|
||||||
|
formatKeySequence(
|
||||||
|
keymap.getCommandBindings({ visibility: "registered", commands: ["prompt.clear"] }).get("prompt.clear")?.[0]
|
||||||
|
?.sequence,
|
||||||
|
props.tuiConfig,
|
||||||
|
) ?? "",
|
||||||
|
)
|
||||||
const busy = createMemo(() => props.state().phase === "running")
|
const busy = createMemo(() => props.state().phase === "running")
|
||||||
const armed = createMemo(() => props.state().interrupt > 0)
|
const armed = createMemo(() => props.state().interrupt > 0)
|
||||||
const exiting = createMemo(() => props.state().exit > 0)
|
const exiting = createMemo(() => props.state().exit > 0)
|
||||||
@@ -438,62 +504,74 @@ export function RunFooterView(props: RunFooterViewProps) {
|
|||||||
props.onRequestExit?.(undefined)
|
props.onRequestExit?.(undefined)
|
||||||
})
|
})
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
useBindings(() => ({
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled: active().type === "prompt" && route().type === "composer" && !composer.visible(),
|
enabled: active().type === "prompt" && route().type === "composer" && !composer.visible(),
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
id: "command.palette.show",
|
name: "command.palette.show",
|
||||||
title: "Open command palette",
|
title: "Open command palette",
|
||||||
group: "Prompt",
|
category: "Prompt",
|
||||||
run: openCommand,
|
run: openCommand,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "variant.cycle",
|
name: "variant.cycle",
|
||||||
title: "Cycle model variant",
|
title: "Cycle model variant",
|
||||||
group: "Model",
|
category: "Model",
|
||||||
run: props.onCycle,
|
run: props.onCycle,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
bindings: [
|
||||||
|
...props.tuiConfig.keybinds.get("command.palette.show"),
|
||||||
|
...props.tuiConfig.keybinds.get("variant.cycle"),
|
||||||
|
],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
useBindings(() => ({
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled: active().type === "prompt" && route().type === "composer" && foregroundSubagents() && !!props.onBackground,
|
enabled: active().type === "prompt" && route().type === "composer" && foregroundSubagents() && !!props.onBackground,
|
||||||
priority: 1,
|
priority: 1,
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
id: "session.background",
|
name: "session.background",
|
||||||
title: "Background subagents",
|
title: "Background subagents",
|
||||||
group: "Session",
|
category: "Session",
|
||||||
run: () => props.onBackground?.(),
|
run: () => props.onBackground?.(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
bindings: props.tuiConfig.keybinds.get("session.background"),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
useBindings(() => ({
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled: active().type === "prompt" && route().type === "composer" && tabs().length > 0,
|
enabled: active().type === "prompt" && route().type === "composer" && tabs().length > 0,
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
id: "session.child.first",
|
name: "session.child.first",
|
||||||
title: "View subagents",
|
title: "View subagents",
|
||||||
group: "Session",
|
category: "Session",
|
||||||
run: openSubagentMenu,
|
run: openSubagentMenu,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
bindings: props.tuiConfig.keybinds.get("session.child.first"),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
useBindings(() => ({
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled: active().type === "prompt" && route().type === "composer" && queuedPrompts().length > 0,
|
enabled: active().type === "prompt" && route().type === "composer" && queuedPrompts().length > 0,
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
id: "session.queued_prompts",
|
name: "session.queued_prompts",
|
||||||
title: "Manage queued prompts",
|
title: "Manage queued prompts",
|
||||||
group: "Session",
|
category: "Session",
|
||||||
run: openQueuedMenu,
|
run: openQueuedMenu,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
bindings: props.tuiConfig.keybinds.get("session.queued_prompts"),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
useBindings(() => ({
|
||||||
|
mode: OPENCODE_BASE_MODE,
|
||||||
enabled:
|
enabled:
|
||||||
active().type === "prompt" &&
|
active().type === "prompt" &&
|
||||||
route().type === "subagent" &&
|
route().type === "subagent" &&
|
||||||
@@ -502,10 +580,9 @@ export function RunFooterView(props: RunFooterViewProps) {
|
|||||||
priority: 1,
|
priority: 1,
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
id: "subagent.interrupt",
|
name: "subagent.interrupt",
|
||||||
title: "Interrupt subagent",
|
title: "Interrupt subagent",
|
||||||
group: "Session",
|
category: "Session",
|
||||||
bind: "ctrl+d",
|
|
||||||
run: () => {
|
run: () => {
|
||||||
const current = selectedTab()
|
const current = selectedTab()
|
||||||
if (current?.status !== "running") {
|
if (current?.status !== "running") {
|
||||||
@@ -516,6 +593,7 @@ export function RunFooterView(props: RunFooterViewProps) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
bindings: [{ key: "ctrl+d", desc: "Interrupt subagent", group: "Subagents", cmd: "subagent.interrupt" }],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import { ServerConnection } from "../services/server-connection"
|
|||||||
import { waitForCatalogReady } from "./catalog.shared"
|
import { waitForCatalogReady } from "./catalog.shared"
|
||||||
import { INTERACTIVE_INPUT_ERROR, resolveInteractiveStdin } from "./runtime.stdin"
|
import { INTERACTIVE_INPUT_ERROR, resolveInteractiveStdin } from "./runtime.stdin"
|
||||||
import type { RunInput, RunTuiConfig } from "./types"
|
import type { RunInput, RunTuiConfig } from "./types"
|
||||||
import { readStdin } from "../util/io"
|
|
||||||
import { setTimeout } from "node:timers/promises"
|
|
||||||
|
|
||||||
export type MiniCommandInput = {
|
export type MiniCommandInput = {
|
||||||
server: ServerConnection.Resolved
|
server: ServerConnection.Resolved
|
||||||
@@ -24,7 +22,7 @@ export type MiniCommandInput = {
|
|||||||
type Session = Awaited<ReturnType<OpenCodeClient["session"]["get"]>>
|
type Session = Awaited<ReturnType<OpenCodeClient["session"]["get"]>>
|
||||||
export async function runMini(input: MiniCommandInput) {
|
export async function runMini(input: MiniCommandInput) {
|
||||||
validate(input)
|
validate(input)
|
||||||
const initialInput = mergeInput(process.stdin.isTTY ? undefined : await readStdin(), input.prompt)
|
const initialInput = mergeInput(process.stdin.isTTY ? undefined : await Bun.stdin.text(), input.prompt)
|
||||||
const runtimeTask = import("./runtime")
|
const runtimeTask = import("./runtime")
|
||||||
const directory = localDirectory()
|
const directory = localDirectory()
|
||||||
|
|
||||||
@@ -125,7 +123,7 @@ async function validateAgent(sdk: OpenCodeClient, directory: string, name?: stri
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (agent) return name
|
if (agent) return name
|
||||||
await setTimeout(25)
|
await Bun.sleep(25)
|
||||||
}
|
}
|
||||||
if (!agents) {
|
if (!agents) {
|
||||||
warning("failed to list agents. Falling back to default agent")
|
warning("failed to list agents. Falling back to default agent")
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { EventSubscribeOutput, OpenCodeClient } from "@opencode-ai/client/promise"
|
import type { EventSubscribeOutput, OpenCodeClient } from "@opencode-ai/client/promise"
|
||||||
import { SessionMessage } from "@opencode-ai/schema/session-message"
|
import { SessionMessage } from "@opencode-ai/schema/session-message"
|
||||||
import { EOL } from "node:os"
|
import { EOL } from "node:os"
|
||||||
import { readFile } from "node:fs/promises"
|
|
||||||
import { UI } from "./ui"
|
import { UI } from "./ui"
|
||||||
import type { MiniToolPart } from "./types"
|
import type { MiniToolPart } from "./types"
|
||||||
|
|
||||||
@@ -479,11 +478,11 @@ async function prepareFile(file: File) {
|
|||||||
if (file.mime !== "text/plain") {
|
if (file.mime !== "text/plain") {
|
||||||
const uri = file.url.startsWith("data:")
|
const uri = file.url.startsWith("data:")
|
||||||
? file.url
|
? file.url
|
||||||
: `data:${file.mime};base64,${(await readFile(new URL(file.url))).toString("base64")}`
|
: `data:${file.mime};base64,${Buffer.from(await Bun.file(new URL(file.url)).arrayBuffer()).toString("base64")}`
|
||||||
return { attachment: { uri, mime: file.mime, name: file.filename } }
|
return { attachment: { uri, mime: file.mime, name: file.filename } }
|
||||||
}
|
}
|
||||||
const content = file.url.startsWith("data:")
|
const content = file.url.startsWith("data:")
|
||||||
? Buffer.from(file.url.slice(file.url.indexOf(",") + 1), "base64").toString("utf8")
|
? Buffer.from(file.url.slice(file.url.indexOf(",") + 1), "base64").toString("utf8")
|
||||||
: await readFile(new URL(file.url), "utf8")
|
: await Bun.file(new URL(file.url)).text()
|
||||||
return { text: `<file name="${file.filename}">\n${content}\n</file>` }
|
return { text: `<file name="${file.filename}">\n${content}\n</file>` }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
// the current draft is saved and history begins. Arrowing past the end
|
// the current draft is saved and history begins. Arrowing past the end
|
||||||
// restores the draft.
|
// restores the draft.
|
||||||
export { displayCharAt, displaySlice, mentionTriggerIndex } from "@opencode-ai/tui/prompt/display"
|
export { displayCharAt, displaySlice, mentionTriggerIndex } from "@opencode-ai/tui/prompt/display"
|
||||||
import { stringWidth } from "@opencode-ai/tui/util/string-width"
|
|
||||||
import type { RunPrompt } from "./types"
|
import type { RunPrompt } from "./types"
|
||||||
|
|
||||||
const HISTORY_LIMIT = 200
|
const HISTORY_LIMIT = 200
|
||||||
@@ -103,7 +102,7 @@ export function movePromptHistory(state: PromptHistoryState, dir: -1 | 1, text:
|
|||||||
return { state, apply: false }
|
return { state, apply: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir === 1 && cursor !== stringWidth(text)) {
|
if (dir === 1 && cursor !== Bun.stringWidth(text)) {
|
||||||
return { state, apply: false }
|
return { state, apply: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +136,7 @@ export function movePromptHistory(state: PromptHistoryState, dir: -1 | 1, text:
|
|||||||
index: null,
|
index: null,
|
||||||
},
|
},
|
||||||
text: state.draft,
|
text: state.draft,
|
||||||
cursor: stringWidth(state.draft),
|
cursor: Bun.stringWidth(state.draft),
|
||||||
apply: true,
|
apply: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,7 +147,7 @@ export function movePromptHistory(state: PromptHistoryState, dir: -1 | 1, text:
|
|||||||
index: idx,
|
index: idx,
|
||||||
},
|
},
|
||||||
text: state.items[idx].text,
|
text: state.items[idx].text,
|
||||||
cursor: dir === -1 ? 0 : stringWidth(state.items[idx].text),
|
cursor: dir === -1 ? 0 : Bun.stringWidth(state.items[idx].text),
|
||||||
apply: true,
|
apply: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { FSUtil } from "@opencode-ai/core/fs-util"
|
|||||||
import { Model } from "@opencode-ai/schema/model"
|
import { Model } from "@opencode-ai/schema/model"
|
||||||
import { open } from "node:fs/promises"
|
import { open } from "node:fs/promises"
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
import { readStdin } from "../util/io"
|
|
||||||
import { ServerConnection } from "../services/server-connection"
|
import { ServerConnection } from "../services/server-connection"
|
||||||
import { loadRunAgents, waitForCatalogReady } from "./catalog.shared"
|
import { loadRunAgents, waitForCatalogReady } from "./catalog.shared"
|
||||||
import { runNonInteractivePrompt } from "./noninteractive"
|
import { runNonInteractivePrompt } from "./noninteractive"
|
||||||
@@ -49,7 +48,7 @@ async function run(input: RunCommandInput) {
|
|||||||
if (input.fork && !input.continue && !input.session) fail("--fork requires --continue or --session")
|
if (input.fork && !input.continue && !input.session) fail("--fork requires --continue or --session")
|
||||||
const root = process.env.PWD ?? process.cwd()
|
const root = process.env.PWD ?? process.cwd()
|
||||||
const directory = localDirectory(root)
|
const directory = localDirectory(root)
|
||||||
const message = mergeInput(formatMessage(input.message), process.stdin.isTTY ? undefined : await readStdin())
|
const message = mergeInput(formatMessage(input.message), process.stdin.isTTY ? undefined : await Bun.stdin.text())
|
||||||
if (!message?.trim()) fail("You must provide a message")
|
if (!message?.trim()) fail("You must provide a message")
|
||||||
const files = await Promise.all(input.file.map((file) => prepareFile(file, root)))
|
const files = await Promise.all(input.file.map((file) => prepareFile(file, root)))
|
||||||
const prepared = { directory, message, files }
|
const prepared = { directory, message, files }
|
||||||
|
|||||||
@@ -10,7 +10,9 @@
|
|||||||
// back to the usual two-press exit sequence through RunFooter.requestExit().
|
// back to the usual two-press exit sequence through RunFooter.requestExit().
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { CliRenderEvents, createCliRenderer, type CliRenderer, type ScrollbackWriter } from "@opentui/core"
|
import { CliRenderEvents, createCliRenderer, type CliRenderer, type ScrollbackWriter } from "@opentui/core"
|
||||||
|
import { createDefaultOpenTuiKeymap } from "@opentui/keymap/opentui"
|
||||||
import { Global } from "@opencode-ai/core/global"
|
import { Global } from "@opencode-ai/core/global"
|
||||||
|
import { registerOpencodeKeymap } from "@opencode-ai/tui/keymap"
|
||||||
import { isDefaultTitle } from "@opencode-ai/tui/util/session"
|
import { isDefaultTitle } from "@opencode-ai/tui/util/session"
|
||||||
import { Locale } from "@opencode-ai/tui/util/locale"
|
import { Locale } from "@opencode-ai/tui/util/locale"
|
||||||
import { resolveInteractiveStdin } from "./runtime.stdin"
|
import { resolveInteractiveStdin } from "./runtime.stdin"
|
||||||
@@ -165,6 +167,8 @@ function queueSplash(
|
|||||||
export async function createRuntimeLifecycle(input: LifecycleInput): Promise<Lifecycle> {
|
export async function createRuntimeLifecycle(input: LifecycleInput): Promise<Lifecycle> {
|
||||||
const source = resolveInteractiveStdin()
|
const source = resolveInteractiveStdin()
|
||||||
const footerTask = import("./footer")
|
const footerTask = import("./footer")
|
||||||
|
let unregisterKeymap: (() => void) | undefined
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const renderer = await createCliRenderer({
|
const renderer = await createCliRenderer({
|
||||||
stdin: source.stdin,
|
stdin: source.stdin,
|
||||||
@@ -183,6 +187,8 @@ export async function createRuntimeLifecycle(input: LifecycleInput): Promise<Lif
|
|||||||
})
|
})
|
||||||
const [theme, tuiConfig] = await Promise.all([resolveRunTheme(renderer), input.tuiConfig])
|
const [theme, tuiConfig] = await Promise.all([resolveRunTheme(renderer), input.tuiConfig])
|
||||||
renderer.setBackgroundColor(theme.background)
|
renderer.setBackgroundColor(theme.background)
|
||||||
|
const keymap = createDefaultOpenTuiKeymap(renderer)
|
||||||
|
unregisterKeymap = registerOpencodeKeymap(keymap, renderer, tuiConfig)
|
||||||
const state: SplashState = {
|
const state: SplashState = {
|
||||||
entry: false,
|
entry: false,
|
||||||
exit: false,
|
exit: false,
|
||||||
@@ -227,6 +233,7 @@ export async function createRuntimeLifecycle(input: LifecycleInput): Promise<Lif
|
|||||||
history: input.history,
|
history: input.history,
|
||||||
theme,
|
theme,
|
||||||
wrote,
|
wrote,
|
||||||
|
keymap,
|
||||||
tuiConfig,
|
tuiConfig,
|
||||||
diffStyle: tuiConfig.diff_style ?? "auto",
|
diffStyle: tuiConfig.diff_style ?? "auto",
|
||||||
onPermissionReply: input.onPermissionReply,
|
onPermissionReply: input.onPermissionReply,
|
||||||
@@ -326,6 +333,7 @@ export async function createRuntimeLifecycle(input: LifecycleInput): Promise<Lif
|
|||||||
footer.close()
|
footer.close()
|
||||||
await footer.idle().catch(() => {})
|
await footer.idle().catch(() => {})
|
||||||
footer.destroy()
|
footer.destroy()
|
||||||
|
unregisterKeymap?.()
|
||||||
shutdown(renderer)
|
shutdown(renderer)
|
||||||
if (!wroteExit) {
|
if (!wroteExit) {
|
||||||
process.stdout.write("\n")
|
process.stdout.write("\n")
|
||||||
@@ -383,6 +391,7 @@ export async function createRuntimeLifecycle(input: LifecycleInput): Promise<Lif
|
|||||||
close,
|
close,
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
unregisterKeymap?.()
|
||||||
source.cleanup?.()
|
source.cleanup?.()
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { readFile } from "node:fs/promises"
|
|
||||||
import type {
|
import type {
|
||||||
EventSubscribeOutput,
|
EventSubscribeOutput,
|
||||||
OpenCodeClient,
|
OpenCodeClient,
|
||||||
@@ -162,7 +161,7 @@ async function prepareFile(file: RunFilePart) {
|
|||||||
if (file.mime !== "text/plain") return { attachment: { uri: file.url, name: file.filename } }
|
if (file.mime !== "text/plain") return { attachment: { uri: file.url, name: file.filename } }
|
||||||
const content = file.url.startsWith("data:")
|
const content = file.url.startsWith("data:")
|
||||||
? Buffer.from(file.url.slice(file.url.indexOf(",") + 1), "base64").toString("utf8")
|
? Buffer.from(file.url.slice(file.url.indexOf(",") + 1), "base64").toString("utf8")
|
||||||
: await readFile(new URL(file.url), "utf8")
|
: await Bun.file(new URL(file.url)).text()
|
||||||
return { text: `<file name="${file.filename}">\n${content}\n</file>` }
|
return { text: `<file name="${file.filename}">\n${content}\n</file>` }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import "./plugin-runtime.promise"
|
|
||||||
import "./plugin-runtime.effect"
|
|
||||||
|
|
||||||
process.stdout.on("error", (error) => {
|
|
||||||
if ("code" in error && error.code === "EPIPE") return
|
|
||||||
throw error
|
|
||||||
})
|
|
||||||
|
|
||||||
await import("../index")
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import {
|
|
||||||
Agent,
|
|
||||||
Command,
|
|
||||||
Connection,
|
|
||||||
Credential,
|
|
||||||
Integration,
|
|
||||||
Model,
|
|
||||||
Plugin,
|
|
||||||
Provider,
|
|
||||||
Reference,
|
|
||||||
Skill,
|
|
||||||
} from "@opencode-ai/plugin/v2/effect"
|
|
||||||
import { Tool } from "@opencode-ai/plugin/v2/effect/tool"
|
|
||||||
|
|
||||||
const key = Symbol.for("opencode.plugin.v2.effect")
|
|
||||||
;(globalThis as typeof globalThis & { [key]?: unknown })[key] = {
|
|
||||||
Agent,
|
|
||||||
Command,
|
|
||||||
Connection,
|
|
||||||
Credential,
|
|
||||||
Integration,
|
|
||||||
Model,
|
|
||||||
Plugin,
|
|
||||||
Provider,
|
|
||||||
Reference,
|
|
||||||
Skill,
|
|
||||||
Tool,
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import {
|
|
||||||
Agent,
|
|
||||||
Command,
|
|
||||||
Connection,
|
|
||||||
Credential,
|
|
||||||
Integration,
|
|
||||||
Model,
|
|
||||||
Plugin,
|
|
||||||
Provider,
|
|
||||||
Reference,
|
|
||||||
Skill,
|
|
||||||
} from "@opencode-ai/plugin/v2"
|
|
||||||
|
|
||||||
const key = Symbol.for("opencode.plugin.v2.promise")
|
|
||||||
;(globalThis as typeof globalThis & { [key]?: unknown })[key] = {
|
|
||||||
Agent,
|
|
||||||
Command,
|
|
||||||
Connection,
|
|
||||||
Credential,
|
|
||||||
Integration,
|
|
||||||
Model,
|
|
||||||
Plugin,
|
|
||||||
Provider,
|
|
||||||
Reference,
|
|
||||||
Skill,
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
const platforms = ["darwin", "linux", "win32"] as const
|
|
||||||
|
|
||||||
export type NodeTarget = ReturnType<typeof nodeTarget>
|
|
||||||
|
|
||||||
export function nodeTarget(platform: string, arch: string) {
|
|
||||||
if (!platforms.includes(platform as (typeof platforms)[number]) || (arch !== "arm64" && arch !== "x64")) {
|
|
||||||
throw new Error(`Unsupported Node executable target: ${platform}-${arch}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetPlatform = platform as (typeof platforms)[number]
|
|
||||||
const targetArch = arch as "arm64" | "x64"
|
|
||||||
const nodePtyPackage = `@lydell/node-pty-${targetPlatform}-${targetArch}`
|
|
||||||
const parcelWatcherPackage = `@parcel/watcher-${targetPlatform}-${targetArch}${targetPlatform === "linux" ? "-glibc" : ""}`
|
|
||||||
|
|
||||||
return {
|
|
||||||
platform: targetPlatform,
|
|
||||||
arch: targetArch,
|
|
||||||
nodePtyPackage,
|
|
||||||
nodePtyEntryAsset: `${nodePtyPackage}/lib/index.js`,
|
|
||||||
parcelWatcherPackage,
|
|
||||||
parcelWatcherAsset: `${parcelWatcherPackage}/watcher.node`,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const photonWasmAsset = "@silvia-odwyer/photon-node/photon_rs_bg.wasm"
|
|
||||||
export const nodeExecArgv = ["--experimental-ffi", "--use-system-ca", "--disable-warning=ExperimentalWarning"] as const
|
|
||||||
|
|
||||||
export const attentionSoundAssets = [
|
|
||||||
"@opencode-ai/ui/audio/bip-bop-01.mp3",
|
|
||||||
"@opencode-ai/ui/audio/bip-bop-03.mp3",
|
|
||||||
"@opencode-ai/ui/audio/staplebops-06.mp3",
|
|
||||||
"@opencode-ai/ui/audio/nope-03.mp3",
|
|
||||||
"@opencode-ai/ui/audio/yup-01.mp3",
|
|
||||||
] as const
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user